Merge branch 'master' of https://github.com/highfidelity/hifi into oldPropsFilters

This commit is contained in:
ZappoMan 2018-01-02 15:47:36 -08:00
commit f639e950e9
164 changed files with 2239 additions and 1639 deletions

27
BUILD_LINUX_CHEATSHEET.md Normal file
View file

@ -0,0 +1,27 @@
# this guide is specific to Ubuntu 16.04.
# deb packages of High Fidelity domain server and assignment client are stored on debian.highfidelity.com
sudo su -
apt-get -y update
apt-get install -y software-properties-common
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 15FF1AAE
add-apt-repository "deb http://debian.highfidelity.com stable main"
apt-get -y update
apt-get install -y hifi-domain-server
apt-get install -y hifi-assignment-client
# When installing master/dev builds, the packages are slightly different and you just need to change the last 2 steps to:
apt-get install -y hifi-dev-domain-server
apt-get install -y hifi-dev-assignment-client
# domain server and assignment clients should already be running. The processes are controlled via:
systemctl start hifi-domain-server
systemctl stop hifi-domain-server
# Once the machine is setup and processes are running you should ensure that your firewall exposes port 40100 on TCP and all UDP ports. This will get your domain up and running and you could connect to it (for now) by using High Fidelity Interface and typing in the IP for the place name. (further customizations can be done via http://IPAddress:40100).
# The server always depends on both hifi-domain-server and hifi-assignment-client running at the same time.
# As an additional step, you should ensure that your packages are automatically updated when a new version goes out. You could, for example, set the automatic update checks to happen every hour (though this could potentially result in the domain being unreachable for a whole hour by new clients when they are released - adjust the update checks accordingly).
To do this you can modify /etc/crontab by adding the following lines
0 */1 * * * root apt-get update
1 */1 * * * root apt-get install --only-upgrade -y hifi-domain-server
2 */1 * * * root apt-get install --only-upgrade -y hifi-assignment-client

View file

@ -214,7 +214,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
uint64_t getTimestamp() const override {
return _lastEncodeTime;
}
const AvatarSharedPointer& getAvatar() const { return _avatar; }
AvatarSharedPointer getAvatar() const { return _avatar; }
private:
AvatarSharedPointer _avatar;
@ -326,7 +326,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
int remainingAvatars = (int)sortedAvatars.size();
while (!sortedAvatars.empty()) {
const auto& avatarData = sortedAvatars.top().getAvatar();
const auto avatarData = sortedAvatars.top().getAvatar();
sortedAvatars.pop();
remainingAvatars--;

View file

@ -12,8 +12,10 @@ function(JOIN VALUES GLUE OUTPUT)
endfunction()
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg)
if (NOT DEV_BUILD)
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg)
endif()
# set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "LeapMotion")
@ -80,7 +82,9 @@ qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
# add them to the interface source files
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
if (NOT DEV_BUILD)
list(APPEND INTERFACE_SRCS ${INTERFACE_QML_QRC})
endif()
if (UNIX)
install(

View file

@ -0,0 +1,18 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
Rectangle {
width: 100
height: 100
color: "white"
Rectangle {
width: 10
height: 10
color: "red"
}
Label {
text: OverlayWindowTestString
anchors.centerIn: parent
}
}

View file

@ -22,7 +22,6 @@ Windows.Window {
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
destroyOnCloseButton: false
property var source;
property var component;
property var dynamicContent;
// Keyboard control properties in case needed by QML content.
@ -35,28 +34,9 @@ Windows.Window {
dynamicContent.destroy();
dynamicContent = null;
}
component = Qt.createComponent(source);
console.log("Created component " + component + " from source " + source);
}
onComponentChanged: {
console.log("Component changed to " + component)
populate();
}
function populate() {
console.log("Populate called: dynamicContent " + dynamicContent + " component " + component);
if (!dynamicContent && component) {
if (component.status == Component.Error) {
console.log("Error loading component:", component.errorString());
} else if (component.status == Component.Ready) {
console.log("Building dynamic content");
dynamicContent = component.createObject(contentHolder);
} else {
console.log("Component not yet ready, connecting to status change");
component.statusChanged.connect(populate);
}
}
QmlSurface.load(source, contentHolder, function(newObject) {
dynamicContent = newObject;
});
}
// Handle message traffic from the script that launched us to the loaded QML

View file

@ -29,12 +29,12 @@ Original.Button {
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
style: ButtonStyle {

View file

@ -31,12 +31,12 @@ Original.CheckBox {
activeFocusOnPress: true
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
// TODO: doesnt works for QQC1. check with QQC2
// onHovered: {
// tabletInterface.playSound(TabletEnums.ButtonHover);
// Tablet.playSound(TabletEnums.ButtonHover);
// }
style: CheckBoxStyle {

View file

@ -36,12 +36,12 @@ CheckBox {
hoverEnabled: true
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}

View file

@ -27,12 +27,12 @@ Original.Button {
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
style: ButtonStyle {

View file

@ -41,13 +41,13 @@ Item {
onContainsMouseChanged: {
if (containsMouse) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
mouse.accepted = true;
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
webEntity.synthesizeKeyPress(glyph);
webEntity.synthesizeKeyPress(glyph, mirrorText);

View file

@ -30,12 +30,12 @@ Original.RadioButton {
readonly property int checkRadius: 2
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
// TODO: doesnt works for QQC1. check with QQC2
// onHovered: {
// tabletInterface.playSound(TabletEnums.ButtonHover);
// Tablet.playSound(TabletEnums.ButtonHover);
// }
style: RadioButtonStyle {

View file

@ -49,7 +49,7 @@ Item {
}
if (WebEngineView.LoadFailedStatus === loadRequest.status) {
console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
console.log("Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
}
if (WebEngineView.LoadSucceededStatus === loadRequest.status) {

View file

@ -25,13 +25,13 @@ Preference {
id: button
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
preference.trigger();
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
width: 180
anchors.bottom: parent.bottom

View file

@ -41,12 +41,12 @@ Preference {
id: checkBox
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
anchors {

View file

@ -246,12 +246,12 @@ Item {
anchors.fill: parent;
acceptedButtons: Qt.LeftButton;
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
goFunction("hifi://" + hifiUrl);
}
hoverEnabled: true;
onEntered: {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
hoverThunk();
}
onExited: unhoverThunk();
@ -269,7 +269,7 @@ Item {
}
}
function go() {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId));
}
MouseArea {

View file

@ -45,11 +45,13 @@ OriginalDesktop.Desktop {
Toolbar {
id: sysToolbar;
objectName: "com.highfidelity.interface.toolbar.system";
property var tablet: Tablet.getTablet("com.highfidelity.interface.tablet.system");
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
x: sysToolbar.x
y: 50
shown: true
buttonModel: tablet.buttons;
shown: tablet.toolbarMode;
}
Settings {

View file

@ -61,12 +61,12 @@ Rectangle {
scrollGestureEnabled: false;
onClicked: {
Audio.muted = !Audio.muted;
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
drag.target: dragTarget;
onContainsMouseChanged: {
if (containsMouse) {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
}
}
}

View file

@ -33,6 +33,7 @@ Rectangle {
property string itemName;
property string itemId;
property string itemHref;
property string itemAuthor;
property double balanceAfterPurchase;
property bool alreadyOwned: false;
property int itemPrice: -1;
@ -41,10 +42,11 @@ Rectangle {
property bool debugCheckoutSuccess: false;
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
property bool isWearable;
property string referrer;
// Style
color: hifi.colors.white;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
@ -72,7 +74,7 @@ Rectangle {
if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
} else {
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -80,12 +82,12 @@ Rectangle {
if (result.status !== 'success') {
failureErrorText.text = result.message;
root.activeView = "checkoutFailure";
UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemPrice, !root.alreadyOwned, result.message);
UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message);
} else {
root.itemHref = result.data.download_url;
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
root.activeView = "checkoutSuccess";
UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemPrice, !root.alreadyOwned);
UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned);
}
}
@ -115,7 +117,7 @@ Rectangle {
}
onItemIdChanged: {
commerce.inventory();
Commerce.inventory();
itemPreviewImage.source = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg";
}
@ -124,14 +126,14 @@ Rectangle {
}
onItemPriceChanged: {
commerce.balance();
Commerce.balance();
}
Timer {
id: notSetUpTimer;
interval: 200;
onTriggered: {
sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId});
sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId, referrer: referrer});
}
}
@ -203,7 +205,7 @@ Rectangle {
Component.onCompleted: {
purchasesReceived = false;
balanceReceived = false;
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -224,7 +226,7 @@ Rectangle {
Connections {
target: GlobalServices
onMyUsernameChanged: {
commerce.getLoginStatus();
Commerce.getLoginStatus();
}
}
@ -409,7 +411,8 @@ Rectangle {
Rectangle {
id: buyTextContainer;
visible: buyText.text !== "";
anchors.top: parent.top;
anchors.top: cancelPurchaseButton.bottom;
anchors.topMargin: 16;
anchors.left: parent.left;
anchors.right: parent.right;
height: buyText.height + 30;
@ -464,8 +467,8 @@ Rectangle {
enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
anchors.topMargin: buyTextContainer.visible ? 12 : 16;
anchors.top: checkoutActionButtonsContainer.top;
anchors.topMargin: 16;
height: 40;
anchors.left: parent.left;
anchors.right: parent.right;
@ -474,9 +477,9 @@ Rectangle {
if (itemIsJson) {
buyButton.enabled = false;
if (!root.shouldBuyWithControlledFailure) {
commerce.buy(itemId, itemPrice);
Commerce.buy(itemId, itemPrice);
} else {
commerce.buy(itemId, itemPrice, true);
Commerce.buy(itemId, itemPrice, true);
}
} else {
if (urlHandler.canHandleUrl(itemHref)) {
@ -877,6 +880,8 @@ Rectangle {
itemName = message.params.itemName;
root.itemPrice = message.params.itemPrice;
itemHref = message.params.itemHref;
referrer = message.params.referrer;
itemAuthor = message.params.itemAuthor;
setBuyText();
break;
default:
@ -924,11 +929,11 @@ Rectangle {
buyText.text = "";
}
} else {
buyText.text = "This free item <b>will not</b> be added to your <b>Purchases</b>. Non-entities can't yet be purchased for HFC.";
buyTextContainer.color = "#FFD6AD";
buyTextContainer.border.color = "#FAC07D";
buyGlyph.text = hifi.glyphs.alert;
buyGlyph.size = 46;
buyText.text = '<i>This type of item cannot currently be certified, so it will not show up in "My Purchases". You can access it again for free from the Marketplace.</i>';
buyTextContainer.color = hifi.colors.white;
buyTextContainer.border.color = hifi.colors.white;
buyGlyph.text = "";
buyGlyph.size = 0;
}
}
@ -940,8 +945,8 @@ Rectangle {
}
root.balanceReceived = false;
root.purchasesReceived = false;
commerce.inventory();
commerce.balance();
Commerce.inventory();
Commerce.balance();
}
//

View file

@ -31,14 +31,14 @@ Item {
height: mainContainer.height + additionalDropdownHeight;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
sendToParent({method: "needsLogIn"});
} else if (walletStatus === 3) {
commerce.getSecurityImage();
Commerce.getSecurityImage();
} else if (walletStatus > 3) {
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
}
@ -48,7 +48,7 @@ Item {
if (!isLoggedIn) {
sendToParent({method: "needsLogIn"});
} else {
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -61,13 +61,13 @@ Item {
}
Component.onCompleted: {
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
Connections {
target: GlobalServices
onMyUsernameChanged: {
commerce.getLoginStatus();
Commerce.getLoginStatus();
}
}

View file

@ -36,8 +36,8 @@ Rectangle {
property bool isCertificateInvalid: false;
// Style
color: hifi.colors.faintGray;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onCertificateInfoResult: {
if (result.status !== 'success') {
@ -109,7 +109,7 @@ Rectangle {
onCertificateIdChanged: {
if (certificateId !== "") {
commerce.certificateInfo(certificateId);
Commerce.certificateInfo(certificateId);
}
}

View file

@ -38,8 +38,8 @@ Rectangle {
property bool isDebuggingFirstUseTutorial: false;
// Style
color: hifi.colors.white;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
@ -61,7 +61,7 @@ Rectangle {
root.activeView = "firstUseTutorial";
} else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") {
root.activeView = "purchasesMain";
commerce.inventory();
Commerce.inventory();
}
} else {
console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus);
@ -72,7 +72,7 @@ Rectangle {
if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
} else {
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -198,7 +198,7 @@ Rectangle {
Component.onCompleted: {
securityImageResultReceived = false;
purchasesReceived = false;
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -219,7 +219,7 @@ Rectangle {
Connections {
target: GlobalServices
onMyUsernameChanged: {
commerce.getLoginStatus();
Commerce.getLoginStatus();
}
}
@ -234,7 +234,7 @@ Rectangle {
onSendSignalToParent: {
if (msg.method === "authSuccess") {
root.activeView = "initialize";
commerce.getWalletStatus();
Commerce.getWalletStatus();
} else {
sendToScript(msg);
}
@ -255,7 +255,7 @@ Rectangle {
case 'tutorial_finished':
Settings.setValue("isFirstUseOfPurchases", false);
root.activeView = "purchasesMain";
commerce.inventory();
Commerce.inventory();
break;
}
}
@ -595,7 +595,7 @@ Rectangle {
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
console.log("Refreshing Purchases...");
root.pendingInventoryReply = true;
commerce.inventory();
Commerce.inventory();
}
}
}

View file

@ -27,8 +27,8 @@ Item {
property string keyFilePath;
property bool showDebugButtons: true;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onKeyFilePathIfExistsResult: {
root.keyFilePath = path;
@ -37,7 +37,7 @@ Item {
onVisibleChanged: {
if (visible) {
commerce.getKeyFilePathIfExists();
Commerce.getKeyFilePathIfExists();
}
}
@ -55,6 +55,37 @@ Item {
// Style
color: hifi.colors.blueHighlight;
}
HifiControlsUit.Button {
id: clearCachedPassphraseButton;
visible: root.showDebugButtons;
color: hifi.buttons.black;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
anchors.left: helpTitleText.right;
anchors.leftMargin: 20;
height: 40;
width: 150;
text: "DBG: Clear Pass";
onClicked: {
Commerce.setPassphrase("");
sendSignalToWallet({method: 'passphraseReset'});
}
}
HifiControlsUit.Button {
id: resetButton;
visible: root.showDebugButtons;
color: hifi.buttons.red;
colorScheme: hifi.colorSchemes.dark;
anchors.top: clearCachedPassphraseButton.top;
anchors.left: clearCachedPassphraseButton.right;
height: 40;
width: 150;
text: "DBG: RST Wallet";
onClicked: {
Commerce.reset();
sendSignalToWallet({method: 'walletReset'});
}
}
ListModel {
id: helpModel;

View file

@ -30,8 +30,8 @@ Item {
source: "images/wallet-bg.jpg";
}
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
}
//

View file

@ -36,8 +36,8 @@ Item {
source: "images/wallet-bg.jpg";
}
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onSecurityImageResult: {
titleBarSecurityImage.source = "";
@ -50,9 +50,11 @@ Item {
submitPassphraseInputButton.enabled = true;
if (!isAuthenticated) {
errorText.text = "Authentication failed - please try again.";
passphraseField.error = true;
UserActivityLogger.commercePassphraseAuthenticationStatus("auth failure");
} else {
sendSignalToParent({method: 'authSuccess'});
passphraseField.error = false;
UserActivityLogger.commercePassphraseAuthenticationStatus("auth success");
}
}
@ -72,6 +74,7 @@ Item {
// TODO: Fix this unlikely bug
onVisibleChanged: {
if (visible) {
passphraseField.error = false;
passphraseField.focus = true;
sendSignalToParent({method: 'disableHmdPreview'});
} else {
@ -210,7 +213,7 @@ Item {
onAccepted: {
submitPassphraseInputButton.enabled = false;
commerce.setPassphrase(passphraseField.text);
Commerce.setPassphrase(passphraseField.text);
}
}
@ -250,7 +253,7 @@ Item {
source: "image://security/securityImage";
cache: false;
onVisibleChanged: {
commerce.getSecurityImage();
Commerce.getSecurityImage();
}
}
Item {
@ -318,7 +321,7 @@ Item {
text: "Submit"
onClicked: {
submitPassphraseInputButton.enabled = false;
commerce.setPassphrase(passphraseField.text);
Commerce.setPassphrase(passphraseField.text);
}
}

View file

@ -36,8 +36,8 @@ Item {
propagateComposedEvents: false;
}
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onSecurityImageResult: {
passphrasePageSecurityImage.source = "";
passphrasePageSecurityImage.source = "image://security/securityImage";
@ -54,6 +54,9 @@ Item {
// TODO: Fix this unlikely bug
onVisibleChanged: {
if (visible) {
passphraseField.error = false;
passphraseFieldAgain.error = false;
currentPassphraseField.error = false;
if (root.shouldImmediatelyFocus) {
focusFirstTextField();
}
@ -160,7 +163,7 @@ Item {
source: "image://security/securityImage";
cache: false;
onVisibleChanged: {
commerce.getSecurityImage();
Commerce.getSecurityImage();
}
}
Item {
@ -283,7 +286,7 @@ Item {
passphraseFieldAgain.error = false;
currentPassphraseField.error = false;
setErrorText("");
commerce.changePassphrase(currentPassphraseField.text, passphraseField.text);
Commerce.changePassphrase(currentPassphraseField.text, passphraseField.text);
return true;
}
}

View file

@ -27,8 +27,8 @@ Item {
id: root;
property string keyFilePath;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onKeyFilePathIfExistsResult: {
root.keyFilePath = path;
@ -234,7 +234,7 @@ Item {
onVisibleChanged: {
if (visible) {
commerce.getKeyFilePathIfExists();
Commerce.getKeyFilePathIfExists();
}
}

View file

@ -26,8 +26,8 @@ Item {
id: root;
property bool justSubmitted: false;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onSecurityImageResult: {
securityImageChangePageSecurityImage.source = "";

View file

@ -25,8 +25,8 @@ Item {
id: root;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
}
// "Unavailable"

View file

@ -31,13 +31,15 @@ Rectangle {
property bool keyboardRaised: false;
property bool isPassword: false;
anchors.fill: (typeof parent === undefined) ? undefined : parent;
Image {
anchors.fill: parent;
source: "images/wallet-bg.jpg";
}
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
@ -47,7 +49,7 @@ Rectangle {
} else if (walletStatus === 1) {
if (root.activeView !== "walletSetup") {
root.activeView = "walletSetup";
commerce.resetLocalWalletOnly();
Commerce.resetLocalWalletOnly();
var timestamp = new Date();
walletSetup.startingTimestamp = timestamp;
walletSetup.setupAttemptID = generateUUID();
@ -60,8 +62,10 @@ Rectangle {
UserActivityLogger.commercePassphraseEntry("wallet app");
}
} else if (walletStatus === 3) {
root.activeView = "walletHome";
commerce.getSecurityImage();
if (root.activeView !== "walletSetup") {
root.activeView = "walletHome";
Commerce.getSecurityImage();
}
} else {
console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus);
}
@ -71,7 +75,7 @@ Rectangle {
if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
} else if (isLoggedIn) {
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -177,7 +181,7 @@ Rectangle {
if (msg.method === 'walletSetup_finished') {
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
root.activeView = "initialize";
commerce.getWalletStatus();
Commerce.getWalletStatus();
} else if (msg.referrer === 'purchases') {
sendToScript({method: 'goToPurchases'});
} else {
@ -206,17 +210,19 @@ Rectangle {
Connections {
onSendSignalToWallet: {
if (msg.method === 'walletSetup_raiseKeyboard') {
root.keyboardRaised = true;
root.isPassword = msg.isPasswordField;
} else if (msg.method === 'walletSetup_lowerKeyboard') {
root.keyboardRaised = false;
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
root.activeView = "security";
} else if (msg.method === 'walletSecurity_changePassphraseSuccess') {
root.activeView = "security";
} else {
sendToScript(msg);
if (passphraseChange.visible) {
if (msg.method === 'walletSetup_raiseKeyboard') {
root.keyboardRaised = true;
root.isPassword = msg.isPasswordField;
} else if (msg.method === 'walletSetup_lowerKeyboard') {
root.keyboardRaised = false;
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
root.activeView = "security";
} else if (msg.method === 'walletSecurity_changePassphraseSuccess') {
root.activeView = "security";
} else {
sendToScript(msg);
}
}
}
}
@ -257,7 +263,7 @@ Rectangle {
color: hifi.colors.baseGray;
Component.onCompleted: {
commerce.getWalletStatus();
Commerce.getWalletStatus();
}
}
@ -278,7 +284,7 @@ Rectangle {
Connections {
target: GlobalServices
onMyUsernameChanged: {
commerce.getLoginStatus();
Commerce.getLoginStatus();
}
}
@ -292,7 +298,7 @@ Rectangle {
Connections {
onSendSignalToParent: {
if (msg.method === "authSuccess") {
commerce.getWalletStatus();
Commerce.getWalletStatus();
} else {
sendToScript(msg);
}

View file

@ -28,8 +28,8 @@ Item {
property bool historyReceived: false;
property int pendingCount: 0;
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onBalanceResult : {
balanceText.text = result.data.balance;
@ -135,8 +135,8 @@ Item {
onVisibleChanged: {
if (visible) {
historyReceived = false;
commerce.balance();
commerce.history();
Commerce.balance();
Commerce.history();
} else {
refreshTimer.stop();
}
@ -165,8 +165,8 @@ Item {
interval: 4000;
onTriggered: {
console.log("Refreshing Wallet Home...");
commerce.balance();
commerce.history();
Commerce.balance();
Commerce.history();
}
}

View file

@ -41,8 +41,8 @@ Item {
source: "images/wallet-bg.jpg";
}
Hifi.QmlCommerce {
id: commerce;
Connections {
target: Commerce;
onSecurityImageResult: {
if (!exists && root.lastPage === "step_2") {
@ -252,7 +252,7 @@ Item {
height: 50;
text: "Cancel";
onClicked: {
sendSignalToWallet({method: 'walletSetup_cancelClicked'});
sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer });
}
}
}
@ -366,7 +366,7 @@ Item {
onClicked: {
root.lastPage = "step_2";
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
commerce.chooseSecurityImage(securityImagePath);
Commerce.chooseSecurityImage(securityImagePath);
root.activeView = "step_3";
passphraseSelection.clearPassphraseFields();
}
@ -449,7 +449,7 @@ Item {
onVisibleChanged: {
if (visible) {
commerce.getWalletAuthenticatedStatus();
Commerce.getWalletAuthenticatedStatus();
}
}
@ -535,7 +535,7 @@ Item {
onClicked: {
if (passphraseSelection.validateAndSubmitPassphrase()) {
root.lastPage = "step_3";
commerce.generateKeyPair();
Commerce.generateKeyPair();
root.activeView = "step_4";
}
}
@ -668,7 +668,7 @@ Item {
onVisibleChanged: {
if (visible) {
commerce.getKeyFilePathIfExists();
Commerce.getKeyFilePathIfExists();
}
}
}

View file

@ -123,11 +123,11 @@ Item {
hoverEnabled: true
enabled: true
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
newEntityButton.clicked();
}
onEntered: {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
newEntityButton.state = "hover state";
}
onExited: {

View file

@ -1,261 +0,0 @@
import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import "../../styles-uit"
import "../audio" as HifiAudio
Item {
id: tablet
objectName: "tablet"
property int rowIndex: 6 // by default
property int columnIndex: 1 // point to 'go to location'
property int count: (flowMain.children.length - 1)
// used to look up a button by its uuid
function findButtonIndex(uuid) {
if (!uuid) {
return -1;
}
for (var i in flowMain.children) {
var child = flowMain.children[i];
if (child.uuid === uuid) {
return i;
}
}
return -1;
}
function sortButtons() {
var children = [];
for (var i = 0; i < flowMain.children.length; i++) {
children[i] = flowMain.children[i];
}
children.sort(function (a, b) {
if (a.sortOrder === b.sortOrder) {
// subsort by stableOrder, because JS sort is not stable in qml.
return a.stableOrder - b.stableOrder;
} else {
return a.sortOrder - b.sortOrder;
}
});
flowMain.children = children;
}
// called by C++ code when a button should be added to the tablet
function addButtonProxy(properties) {
var component = Qt.createComponent("TabletButton.qml");
var button = component.createObject(flowMain);
// copy all properites to button
var keys = Object.keys(properties).forEach(function (key) {
button[key] = properties[key];
});
// pass a reference to the tabletRoot object to the button.
if (tabletRoot) {
button.tabletRoot = tabletRoot;
} else {
button.tabletRoot = parent.parent;
}
sortButtons();
return button;
}
// called by C++ code when a button should be removed from the tablet
function removeButtonProxy(properties) {
var index = findButtonIndex(properties.uuid);
if (index < 0) {
console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid);
} else {
flowMain.children[index].destroy();
}
}
Rectangle {
id: bgTopBar
height: 90
anchors {
top: parent.top
topMargin: 0
left: parent.left
leftMargin: 0
right: parent.right
rightMargin: 0
}
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#1e1e1e"
}
}
HifiAudio.MicBar {
anchors {
left: parent.left
leftMargin: 30
verticalCenter: parent.verticalCenter
}
}
Item {
width: 150
height: 50
anchors.right: parent.right
anchors.rightMargin: 30
anchors.verticalCenter: parent.verticalCenter
ColumnLayout {
anchors.fill: parent
RalewaySemiBold {
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
RalewaySemiBold {
visible: Account.loggedIn
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if (!Account.loggedIn) {
DialogsManager.showLoginDialog()
} else {
Account.logOut()
}
}
}
}
}
Rectangle {
id: bgMain
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#0f212e"
}
}
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.top: bgTopBar.bottom
anchors.topMargin: 0
Flickable {
id: flickable
width: parent.width
height: parent.height
contentWidth: parent.width
contentHeight: flowMain.childrenRect.height + flowMain.anchors.topMargin + flowMain.anchors.bottomMargin + flowMain.spacing
clip: true
Flow {
id: flowMain
spacing: 16
anchors.right: parent.right
anchors.rightMargin: 30
anchors.left: parent.left
anchors.leftMargin: 30
anchors.bottom: parent.bottom
anchors.bottomMargin: 30
anchors.top: parent.top
anchors.topMargin: 30
}
}
}
function setCurrentItemState(state) {
var index = rowIndex + columnIndex;
if (index >= 0 && index <= count ) {
flowMain.children[index].state = state;
}
}
function nextItem() {
setCurrentItemState("base state");
var nextColumnIndex = (columnIndex + 3 + 1) % 3;
var nextIndex = rowIndex + nextColumnIndex;
if(nextIndex <= count) {
columnIndex = nextColumnIndex;
};
setCurrentItemState("hover state");
}
function previousItem() {
setCurrentItemState("base state");
var prevIndex = (columnIndex + 3 - 1) % 3;
if((rowIndex + prevIndex) <= count){
columnIndex = prevIndex;
}
setCurrentItemState("hover state");
}
function upItem() {
setCurrentItemState("base state");
rowIndex = rowIndex - 3;
if (rowIndex < 0 ) {
rowIndex = (count - (count % 3));
var index = rowIndex + columnIndex;
if(index > count) {
rowIndex = rowIndex - 3;
}
}
setCurrentItemState("hover state");
}
function downItem() {
setCurrentItemState("base state");
rowIndex = rowIndex + 3;
var index = rowIndex + columnIndex;
if (index > count ) {
rowIndex = 0;
}
setCurrentItemState("hover state");
}
function selectItem() {
flowMain.children[rowIndex + columnIndex].clicked();
if (tabletRoot) {
tabletRoot.playButtonClickSound();
}
}
Keys.onRightPressed: nextItem();
Keys.onLeftPressed: previousItem();
Keys.onDownPressed: downItem();
Keys.onUpPressed: upItem();
Keys.onReturnPressed: selectItem();
}

View file

@ -123,7 +123,6 @@ Item {
enabled: true
preventStealing: true
onClicked: {
console.log("Tablet Button Clicked!");
if (tabletButton.inDebugMode) {
if (tabletButton.isActive) {
tabletButton.isActive = false;
@ -133,12 +132,12 @@ Item {
}
tabletButton.clicked();
if (tabletRoot) {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
}
}
onEntered: {
tabletButton.isEntered = true;
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
if (tabletButton.isActive) {
tabletButton.state = "hover active state";

View file

@ -0,0 +1,159 @@
import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import "."
import "../../styles-uit"
import "../audio" as HifiAudio
Item {
id: tablet
objectName: "tablet"
property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system");
Rectangle {
id: bgTopBar
height: 90
anchors {
top: parent.top
left: parent.left
right: parent.right
}
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#1e1e1e"
}
}
HifiAudio.MicBar {
anchors {
left: parent.left
leftMargin: 30
verticalCenter: parent.verticalCenter
}
}
Item {
width: 150
height: 50
anchors.right: parent.right
anchors.rightMargin: 30
anchors.verticalCenter: parent.verticalCenter
ColumnLayout {
anchors.fill: parent
RalewaySemiBold {
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
RalewaySemiBold {
visible: Account.loggedIn
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if (!Account.loggedIn) {
DialogsManager.showLoginDialog()
} else {
Account.logOut()
}
}
}
}
}
Rectangle {
id: bgMain
clip: true
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#0f212e"
}
}
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.top: bgTopBar.bottom
GridView {
id: flickable
anchors.top: parent.top
anchors.topMargin: 15
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: cellWidth * 3
cellHeight: 145
cellWidth: 145
model: tabletProxy.buttons
delegate: Item {
width: flickable.cellWidth
height: flickable.cellHeight
property var proxy: modelData
TabletButton {
id: tabletButton
anchors.centerIn: parent
onClicked: modelData.clicked()
state: wrapper.GridView.isCurrentItem ? "hover state" : "base state"
}
Connections {
target: modelData;
onPropertiesChanged: {
updateProperties();
}
}
Component.onCompleted: updateProperties()
function updateProperties() {
var keys = Object.keys(modelData.properties).forEach(function (key) {
if (tabletButton[key] !== modelData.properties[key]) {
tabletButton[key] = modelData.properties[key];
}
});
}
}
}
}
Keys.onRightPressed: flickable.moveCurrentIndexRight();
Keys.onLeftPressed: flickable.moveCurrentIndexLeft();
Keys.onDownPressed: flickable.moveCurrentIndexDown();
Keys.onUpPressed: flickable.moveCurrentIndexUp();
Keys.onReturnPressed: {
if (flickable.currentItem) {
flickable.currentItem.proxy.clicked();
if (tabletRoot) {
tabletRoot.playButtonClickSound();
}
}
}
}

View file

@ -77,12 +77,12 @@ FocusScope {
anchors.fill: parent
hoverEnabled: true
onEntered: {
tabletInterface.playSound(TabletEnums.ButtonHover);
Tablet.playSound(TabletEnums.ButtonHover);
listView.currentIndex = index
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
Tablet.playSound(TabletEnums.ButtonClick);
root.selected(item);
}
}

View file

@ -68,37 +68,36 @@ Item {
function loadSource(url) {
tabletApps.clear();
loader.source = ""; // make sure we load the qml fresh each time.
loader.source = url;
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
loader.load(url)
}
function loadQMLOnTop(url) {
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
loader.source = "";
loader.source = tabletApps.get(currentApp).appUrl;
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
loader.item.gotoPreviousApp = true;
}
loader.load(tabletApps.get(currentApp).appUrl, function(){
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
loader.item.gotoPreviousApp = true;
}
})
}
function loadWebOnTop(url, injectJavaScriptUrl) {
tabletApps.append({"appUrl": loader.source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url});
loader.item.url = tabletApps.get(currentApp).appWebUrl;
loader.item.scriptUrl = tabletApps.get(currentApp).scriptUrl;
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
loader.item.gotoPreviousApp = true;
}
function loadWebContent(source, url, injectJavaScriptUrl) {
tabletApps.append({"appUrl": source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url});
loader.load(source, function() {
loader.item.scriptURL = injectJavaScriptUrl;
loader.item.url = url;
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
loader.item.gotoPreviousApp = true;
}
});
}
function loadWebBase() {
loader.source = "";
loader.source = "TabletWebView.qml";
function loadWebBase(url, injectJavaScriptUrl) {
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
}
function loadTabletWebBase() {
loader.source = "";
loader.source = "./BlocksWebView.qml";
function loadTabletWebBase(url, injectJavaScriptUrl) {
loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl);
}
function returnToPreviousApp() {
@ -110,7 +109,7 @@ Item {
loadSource("TabletWebView.qml");
loadWebUrl(webUrl, scriptUrl);
} else {
loader.source = tabletApps.get(currentApp).appUrl;
loader.load(tabletApps.get(currentApp).appUrl);
}
}
@ -173,47 +172,79 @@ Item {
}
}
Loader {
id: loader
objectName: "loader"
asynchronous: false
width: parent.width
height: parent.height
// Hook up callback for clara.io download from the marketplace.
Connections {
id: eventBridgeConnection
target: eventBridge
onWebEventReceived: {
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
}
}
}
onLoaded: {
if (loader.item.hasOwnProperty("sendToScript")) {
loader.item.sendToScript.connect(tabletRoot.sendToScript);
}
if (loader.item.hasOwnProperty("setRootMenu")) {
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
}
loader.item.forceActiveFocus();
if (openModal) {
openModal.canceled();
openModal.destroy();
openModal = null;
}
if (openBrowser) {
openBrowser.destroy();
openBrowser = null;
// Hook up callback for clara.io download from the marketplace.
Connections {
id: eventBridgeConnection
target: eventBridge
onWebEventReceived: {
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
}
}
}
Item {
id: loader
objectName: "loader";
anchors.fill: parent;
property string source: "";
property var item: null;
signal loaded;
onWidthChanged: {
if (loader.item) {
loader.item.width = loader.width;
}
}
onHeightChanged: {
if (loader.item) {
loader.item.height = loader.height;
}
}
function load(newSource, callback) {
if (loader.source == newSource) {
loader.loaded();
return;
}
if (loader.item) {
loader.item.destroy();
loader.item = null;
}
QmlSurface.load(newSource, loader, function(newItem) {
loader.item = newItem;
loader.item.width = loader.width;
loader.item.height = loader.height;
loader.loaded();
if (loader.item.hasOwnProperty("sendToScript")) {
loader.item.sendToScript.connect(tabletRoot.sendToScript);
}
if (loader.item.hasOwnProperty("setRootMenu")) {
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
}
loader.item.forceActiveFocus();
if (openModal) {
openModal.canceled();
openModal.destroy();
openModal = null;
}
if (openBrowser) {
openBrowser.destroy();
openBrowser = null;
}
if (callback) {
callback();
}
});
}
}
width: 480
height: 706

View file

@ -59,26 +59,25 @@ Windows.ScrollingWindow {
}
function loadSource(url) {
loader.source = ""; // make sure we load the qml fresh each time.
loader.source = url;
loader.load(url)
}
function loadWebBase() {
loader.source = "";
loader.source = "WindowWebView.qml";
function loadWebContent(source, url, injectJavaScriptUrl) {
loader.load(source, function() {
loader.item.scriptURL = injectJavaScriptUrl;
loader.item.url = url;
if (loader.item.hasOwnProperty("closeButtonVisible")) {
loader.item.closeButtonVisible = false;
}
});
}
function loadTabletWebBase() {
loader.source = "";
loader.source = "./BlocksWebView.qml";
function loadWebBase(url, injectJavaScriptUrl) {
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
}
function loadWebUrl(url, injectedJavaScriptUrl) {
loader.item.url = url;
loader.item.scriptURL = injectedJavaScriptUrl;
if (loader.item.hasOwnProperty("closeButtonVisible")) {
loader.item.closeButtonVisible = false;
}
function loadTabletWebBase(url, injectJavaScriptUrl) {
loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl);
}
// used to send a message from qml to interface script.
@ -111,38 +110,68 @@ Windows.ScrollingWindow {
username = newUsername;
}
Loader {
// Hook up callback for clara.io download from the marketplace.
Connections {
id: eventBridgeConnection
target: eventBridge
onWebEventReceived: {
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
}
}
}
Item {
id: loader
objectName: "loader"
asynchronous: false
objectName: "loader";
property string source: "";
property var item: null;
height: pane.scrollHeight
width: pane.contentWidth
anchors.left: parent.left
anchors.top: parent.top
// Hook up callback for clara.io download from the marketplace.
Connections {
id: eventBridgeConnection
target: eventBridge
onWebEventReceived: {
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
}
signal loaded;
onWidthChanged: {
if (loader.item) {
loader.item.width = loader.width;
}
}
onLoaded: {
if (loader.item.hasOwnProperty("sendToScript")) {
loader.item.sendToScript.connect(tabletRoot.sendToScript);
onHeightChanged: {
if (loader.item) {
loader.item.height = loader.height;
}
if (loader.item.hasOwnProperty("setRootMenu")) {
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
}
function load(newSource, callback) {
if (loader.item) {
loader.item.destroy();
loader.item = null;
}
loader.item.forceActiveFocus();
QmlSurface.load(newSource, loader, function(newItem) {
loader.item = newItem;
loader.item.width = loader.width;
loader.item.height = loader.height;
loader.loaded();
if (loader.item.hasOwnProperty("sendToScript")) {
loader.item.sendToScript.connect(tabletRoot.sendToScript);
}
if (loader.item.hasOwnProperty("setRootMenu")) {
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
}
loader.item.forceActiveFocus();
if (callback) {
callback();
}
});
}
}
implicitWidth: 480
implicitHeight: 706
}

View file

@ -11,6 +11,8 @@ Window {
horizontalSpacers: horizontal
verticalSpacers: !horizontal
}
property var tabletProxy;
property var buttonModel: ListModel {}
hideBackground: true
resizable: false
destroyOnCloseButton: false
@ -23,24 +25,32 @@ Window {
activator: Item {}
property bool horizontal: true
property real buttonSize: 50;
property var buttons: []
property var container: horizontal ? row : column
Settings {
category: "toolbar/" + window.objectName
property alias x: window.x
property alias y: window.y
}
Component {
id: buttonComponent
ToolbarButton {
id: toolbarButton
property var proxy: modelData;
onClicked: proxy.clicked()
Component.onCompleted: updateProperties()
onHorizontalChanged: {
var newParent = horizontal ? row : column;
for (var i in buttons) {
var child = buttons[i];
child.parent = newParent;
if (horizontal) {
child.y = 0
} else {
child.x = 0
Connections {
target: proxy;
onPropertiesChanged: updateProperties();
}
function updateProperties() {
Object.keys(proxy.properties).forEach(function (key) {
if (toolbarButton[key] !== proxy.properties[key]) {
toolbarButton[key] = proxy.properties[key];
}
});
}
}
}
@ -52,97 +62,22 @@ Window {
Row {
id: row
visible: window.horizontal
spacing: 6
Repeater {
model: buttonModel
delegate: buttonComponent
}
}
Column {
id: column
visible: !window.horizontal
spacing: 6
}
Component { id: toolbarButtonBuilder; ToolbarButton { } }
}
function findButtonIndex(name) {
if (!name) {
return -1;
}
for (var i in buttons) {
var child = buttons[i];
if (child.objectName === name) {
return i;
Repeater {
model: buttonModel
delegate: buttonComponent
}
}
return -1;
}
function findButton(name) {
var index = findButtonIndex(name);
if (index < 0) {
return;
}
return buttons[index];
}
function sortButtons() {
var children = [];
for (var i = 0; i < container.children.length; i++) {
children[i] = container.children[i];
}
children.sort(function (a, b) {
if (a.sortOrder === b.sortOrder) {
// subsort by stableOrder, because JS sort is not stable in qml.
return a.stableOrder - b.stableOrder;
} else {
return a.sortOrder - b.sortOrder;
}
});
container.children = children;
}
function addButton(properties) {
properties = properties || {}
// If a name is specified, then check if there's an existing button with that name
// and return it if so. This will allow multiple clients to listen to a single button,
// and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded
var result = findButton(properties.objectName);
if (result) {
for (var property in properties) {
result[property] = properties[property];
}
return result;
}
properties.toolbar = this;
properties.opacity = 0;
result = toolbarButtonBuilder.createObject(container, properties);
buttons.push(result);
result.opacity = 1;
sortButtons();
fadeIn(null);
return result;
}
function removeButton(name) {
var index = findButtonIndex(name);
if (index < -1) {
console.warn("Tried to remove non-existent button " + name);
return;
}
buttons[index].destroy();
buttons.splice(index, 1);
if (buttons.length === 0) {
fadeOut(null);
}
}
}

View file

@ -27,7 +27,8 @@ StateImage {
property string activeHoverIcon: button.activeIcon
property int sortOrder: 100
property int stableSortOrder: 0
property int stableOrder: 0
property var uuid;
signal clicked()

View file

@ -191,6 +191,7 @@
#include <GPUIdent.h>
#include <gl/GLHelpers.h>
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
#include <src/scripting/GooglePolyScriptingInterface.h>
#include <EntityScriptClient.h>
#include <ModelScriptingInterface.h>
@ -698,6 +699,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<EntityScriptClient>();
DependencyManager::set<EntityScriptServerLogClient>();
DependencyManager::set<LimitlessVoiceRecognitionScriptingInterface>();
DependencyManager::set<GooglePolyScriptingInterface>();
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
DependencyManager::set<AvatarBookmarks>();
DependencyManager::set<LocationBookmarks>();
@ -2248,27 +2250,65 @@ extern void setupPreferences();
void Application::initializeUi() {
// Make sure all QML surfaces share the main thread GL context
OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext());
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "OverlayWindowTest.qml" },
[](QQmlContext* context) {
qDebug() << "Whitelist OverlayWindow worked";
context->setContextProperty("OverlayWindowTestString", "TestWorked");
});
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "hifi/audio/Audio.qml" },
[](QQmlContext* context) {
qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked";
});
AddressBarDialog::registerType();
ErrorDialog::registerType();
LoginDialog::registerType();
Tooltip::registerType();
UpdateDialog::registerType();
QmlCommerce::registerType();
QmlContextCallback callback = [](QQmlContext* context) {
context->setContextProperty("Commerce", new QmlCommerce());
};
OffscreenQmlSurface::addWhitelistContextHandler({
QUrl{ "hifi/commerce/checkout/Checkout.qml" },
QUrl{ "hifi/commerce/common/CommerceLightbox.qml" },
QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" },
QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" },
QUrl{ "hifi/commerce/common/SortableListModel.qml" },
QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" },
QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" },
QUrl{ "hifi/commerce/purchases/Purchases.qml" },
QUrl{ "hifi/commerce/wallet/Help.qml" },
QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" },
QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" },
QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" },
QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" },
QUrl{ "hifi/commerce/wallet/Security.qml" },
QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" },
QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" },
QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" },
QUrl{ "hifi/commerce/wallet/SendMoney.qml" },
QUrl{ "hifi/commerce/wallet/Wallet.qml" },
QUrl{ "hifi/commerce/wallet/WalletHome.qml" },
QUrl{ "hifi/commerce/wallet/WalletSetup.qml" },
}, callback);
qmlRegisterType<ResourceImageItem>("Hifi", 1, 0, "ResourceImageItem");
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
qmlRegisterType<WebBrowserSuggestionsEngine>("HifiWeb", 1, 0, "WebBrowserSuggestionsEngine");
{
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
tabletScriptingInterface->getTablet(SYSTEM_TABLET);
}
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create();
auto surfaceContext = offscreenUi->getSurfaceContext();
offscreenUi->setProxyWindow(_window->windowHandle());
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
// support the window management and scripting proxies for VR use
offscreenUi->createDesktop(QString("qrc:///qml/hifi/Desktop.qml"));
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
// FIXME either expose so that dialogs can set this themselves or
// do better detection in the offscreen UI of what has focus
@ -2336,9 +2376,6 @@ void Application::initializeUi() {
surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
surfaceContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
surfaceContext->setContextProperty("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
@ -4244,7 +4281,7 @@ void Application::init() {
getEntities()->init();
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
auto dims = item.getDimensions();
auto dims = item.getScaledDimensions();
auto maxSize = glm::compMax(dims);
if (maxSize <= 0.0f) {
@ -4288,9 +4325,11 @@ void Application::updateLOD(float deltaTime) const {
PerformanceTimer perfTimer("LOD");
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
if (!isThrottleRendering()) {
float batchTime = (float)_gpuContext->getFrameTimerBatchAverage();
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
DependencyManager::get<LODManager>()->autoAdjustLOD(batchTime, engineRunTime, deltaTime);
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
float maxRenderTime = glm::max(gpuTime, glm::max(presentTime, engineRunTime));
DependencyManager::get<LODManager>()->autoAdjustLOD(maxRenderTime, deltaTime);
} else {
DependencyManager::get<LODManager>()->resetLODAdjust();
}
@ -4596,7 +4635,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
_lastAcceptedKeyPress = usecTimestampNow();
setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
}
}
}
@ -5836,9 +5875,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
qScriptRegisterMetaType(scriptEngine.data(),
wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
scriptEngine->registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
// FIXME remove these deprecated names for the tablet scripting interface
scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>().data();
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(toolbarScriptingInterface);
@ -5904,6 +5943,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>().data());
scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get<GooglePolyScriptingInterface>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get()));
@ -7245,13 +7285,17 @@ void Application::updateDisplayMode() {
}
auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto desktop = offscreenUi->getDesktop();
// Make the switch atomic from the perspective of other threads
{
std::unique_lock<std::mutex> lock(_displayPluginLock);
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
bool wasRepositionLocked = false;
if (desktop) {
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
}
if (_displayPlugin) {
disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
@ -7297,7 +7341,6 @@ void Application::updateDisplayMode() {
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
_displayPlugin = newDisplayPlugin;
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
auto desktop = offscreenUi->getDesktop();
if (desktop) {
desktop->setProperty("repositionLocked", wasRepositionLocked);
}

View file

@ -19,6 +19,7 @@
#include "LODManager.h"
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS);
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS);
@ -39,156 +40,95 @@ float LODManager::getLODIncreaseFPS() {
return getDesktopLODIncreaseFPS();
}
void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float deltaTimeSec) {
// We use a "time-weighted running average" of the renderTime and compare it against min/max thresholds
// to determine if we should adjust the level of detail (LOD).
//
// A time-weighted running average has a timescale which determines how fast the average tracks the measured
// value in real-time. Given a step-function in the mesured value, and assuming measurements happen
// faster than the runningAverage is computed, the error between the value and its runningAverage will be
// reduced by 1/e every timescale of real-time that passes.
const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.1f; // sec
//
// Assuming the measured value is affected by logic invoked by the runningAverage bumping up against its
// thresholds, we expect the adjustment to introduce a step-function. We want the runningAverage settle
// to the new value BEFORE we test it aginst its thresholds again. Hence we test on a period that is a few
// multiples of the running average timescale:
const uint64_t LOD_AUTO_ADJUST_PERIOD = 5 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
// really want to count them in our average, so we will ignore the real frame rates and stuff
// our moving average with simulated good data
const int IGNORE_THESE_SAMPLES = 100;
if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) {
_lastStable = _lastUpShift = _lastDownShift = usecTimestampNow();
}
const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f;
const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f;
void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
// compute time-weighted running average renderTime
const float OVERLAY_AND_SWAP_TIME_BUDGET = 2.0f; // msec
float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET;
float maxTime = glm::max(renderTime, engineRunTime);
const float BLEND_TIMESCALE = 0.3f; // sec
const float MIN_DELTA_TIME = 0.001f;
const float safeDeltaTime = glm::max(deltaTimeSec, MIN_DELTA_TIME);
float blend = BLEND_TIMESCALE / safeDeltaTime;
if (blend > 1.0f) {
blend = 1.0f;
// Note: we MUST clamp the blend to 1.0 for stability
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec
if (!_automaticLODAdjust) {
// early exit
return;
}
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxTime; // msec
// translate into fps for legacy implementation
float oldOctreeSizeScale = _octreeSizeScale;
float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime;
_fpsAverageStartWindow.updateAverage(currentFPS);
_fpsAverageDownWindow.updateAverage(currentFPS);
_fpsAverageUpWindow.updateAverage(currentFPS);
quint64 now = usecTimestampNow();
quint64 elapsedSinceDownShift = now - _lastDownShift;
quint64 elapsedSinceUpShift = now - _lastUpShift;
quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable);
quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift;
if (_automaticLODAdjust) {
bool changed = false;
// LOD Downward adjustment
// If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our
// target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift,
// or because we've just started out) then we look at a much longer window to consider whether or not to start
// downshifting.
bool doDownShift = false;
if (_isDownshifting) {
// only consider things if our DOWN_SHIFT time has elapsed...
if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) {
doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS();
if (!doDownShift) {
qCDebug(interfaceapp) << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----";
_isDownshifting = false;
_lastStable = now;
}
}
} else {
doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED
&& _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS());
}
if (doDownShift) {
// Octree items... stepwise adjustment
uint64_t now = usecTimestampNow();
if (currentFPS < getLODDecreaseFPS()) {
if (now > _decreaseFPSExpiry) {
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale *= ADJUST_LOD_DOWN_BY;
_octreeSizeScale *= LOD_AUTO_ADJUST_DECREMENT_FACTOR;
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
}
changed = true;
}
if (changed) {
if (_isDownshifting) {
// subsequent downshift
qCDebug(interfaceapp) << "adjusting LOD DOWN..."
<< "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was "
<< _fpsAverageDownWindow.getAverage()
<< "minimum is:" << getLODDecreaseFPS()
<< "elapsedSinceDownShift:" << elapsedSinceDownShift
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
} else {
// first downshift
qCDebug(interfaceapp) << "adjusting LOD DOWN after initial delay..."
<< "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was "
<< _fpsAverageStartWindow.getAverage()
<< "minimum is:" << getLODDecreaseFPS()
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
}
_lastDownShift = now;
_isDownshifting = true;
qCDebug(interfaceapp) << "adjusting LOD DOWN"
<< "fps =" << currentFPS
<< "targetFPS =" << getLODDecreaseFPS()
<< "octreeSizeScale =" << _octreeSizeScale;
emit LODDecreased();
}
} else {
// LOD Upward adjustment
if (elapsedSinceUpShift > UP_SHIFT_ELPASED) {
if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) {
// Octee items... stepwise adjustment
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
} else {
_octreeSizeScale *= ADJUST_LOD_UP_BY;
}
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
}
changed = true;
}
}
if (changed) {
qCDebug(interfaceapp) << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was "
<< _fpsAverageUpWindow.getAverage()
<< "upshift point is:" << getLODIncreaseFPS()
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
_lastUpShift = now;
_isDownshifting = false;
emit LODIncreased();
}
}
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
}
if (changed) {
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
if (lodToolsDialog) {
lodToolsDialog->reloadSliders();
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
} else if (currentFPS > getLODIncreaseFPS()) {
if (now > _increaseFPSExpiry) {
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
} else {
_octreeSizeScale *= LOD_AUTO_ADJUST_INCREMENT_FACTOR;
}
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
}
qCDebug(interfaceapp) << "adjusting LOD UP"
<< "fps =" << currentFPS
<< "targetFPS =" << getLODDecreaseFPS()
<< "octreeSizeScale =" << _octreeSizeScale;
emit LODIncreased();
}
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
}
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
} else {
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
_decreaseFPSExpiry = _increaseFPSExpiry;
}
if (oldOctreeSizeScale != _octreeSizeScale) {
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
if (lodToolsDialog) {
lodToolsDialog->reloadSliders();
}
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
// to be at middle of target zone. It will drift close to its true value within
// about three few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
float expectedFPS = 0.5f * (getLODIncreaseFPS() + getLODDecreaseFPS());
_avgRenderTime = MSECS_PER_SECOND / expectedFPS;
}
}
void LODManager::resetLODAdjust() {
_fpsAverageStartWindow.reset();
_fpsAverageDownWindow.reset();
_fpsAverageUpWindow.reset();
_lastUpShift = _lastDownShift = usecTimestampNow();
_isDownshifting = false;
_decreaseFPSExpiry = _increaseFPSExpiry = usecTimestampNow() + LOD_AUTO_ADJUST_PERIOD;
}
const float MIN_DECREASE_FPS = 0.5f;
@ -206,7 +146,7 @@ float LODManager::getDesktopLODDecreaseFPS() const {
}
float LODManager::getDesktopLODIncreaseFPS() const {
return glm::max(((float)MSECS_PER_SECOND / _desktopMaxRenderTime) + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS);
return glm::max(((float)MSECS_PER_SECOND / _desktopMaxRenderTime) + INCREASE_LOD_GAP_FPS, MAX_LIKELY_DESKTOP_FPS);
}
void LODManager::setHMDLODDecreaseFPS(float fps) {
@ -222,7 +162,7 @@ float LODManager::getHMDLODDecreaseFPS() const {
}
float LODManager::getHMDLODIncreaseFPS() const {
return glm::max(((float)MSECS_PER_SECOND / _hmdMaxRenderTime) + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS);
return glm::max(((float)MSECS_PER_SECOND / _hmdMaxRenderTime) + INCREASE_LOD_GAP_FPS, MAX_LIKELY_HMD_FPS);
}
QString LODManager::getLODFeedbackText() {

View file

@ -19,29 +19,13 @@
#include <SimpleMovingAverage.h>
#include <render/Args.h>
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 20.0;
const float DEFAULT_HMD_LOD_DOWN_FPS = 20.0;
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0f;
const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0f;
const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec
const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec
const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps
const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps
const float INCREASE_LOD_GAP = 15.0f;
const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts
const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f;
const float UP_SHIFT_WINDOW_IN_SECS = 2.5f;
const int ASSUMED_FPS = 60;
const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS;
const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second
const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS;
const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS;
const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS;
const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
const float ADJUST_LOD_DOWN_BY = 0.9f;
const float ADJUST_LOD_UP_BY = 1.1f;
const float MAX_LIKELY_DESKTOP_FPS = 59.0f; // this is essentially, V-synch - 1 fps
const float MAX_LIKELY_HMD_FPS = 74.0f; // this is essentially, V-synch - 1 fps
const float INCREASE_LOD_GAP_FPS = 15.0f; // fps
// The default value DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
@ -78,7 +62,7 @@ public:
Q_INVOKABLE float getLODIncreaseFPS();
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
void autoAdjustLOD(float batchTime, float engineRunTime, float deltaTimeSec);
void autoAdjustLOD(float renderTime, float realTimeDelta);
void loadSettings();
void saveSettings();
@ -92,21 +76,15 @@ private:
LODManager();
bool _automaticLODAdjust = true;
float _avgRenderTime { 0.0 };
float _avgRenderTime { 0.0f };
float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME };
float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME };
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
int _boundaryLevelAdjust = 0;
quint64 _lastDownShift = 0;
quint64 _lastUpShift = 0;
quint64 _lastStable = 0;
bool _isDownshifting = false; // start out as if we're not downshifting
SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES;
SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES;
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
uint64_t _decreaseFPSExpiry { 0 };
uint64_t _increaseFPSExpiry { 0 };
};
#endif // hifi_LODManager_h

View file

@ -101,7 +101,7 @@ Menu::Menu() {
auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J);
connect(action, &QAction::triggered, [] {
static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml");
static const QUrl tabletUrl("../../hifi/dialogs/TabletRunningScripts.qml");
static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml");
static const QString name("RunningScripts");
qApp->showDialog(widgetUrl, tabletUrl, name);
});
@ -338,7 +338,7 @@ Menu::Menu() {
connect(action, &QAction::triggered, [] {
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
auto hmd = DependencyManager::get<HMDScriptingInterface>();
tablet->loadQMLSource("ControllerSettings.qml");
tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml");
if (!hmd->getShouldShowTablet()) {
hmd->toggleShouldShowTablet();

View file

@ -407,7 +407,7 @@ void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &s
ShapeInfo::PointList points;
pointCollection.push_back(points);
GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getDimensions(), pointCollection.back());
GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getScaledDimensions(), pointCollection.back());
shapeInfo.setPointCollection(pointCollection);
}

View file

@ -150,7 +150,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
float getRadius() const override { return std::static_pointer_cast<Avatar>(_avatar)->getBoundingRadius(); }
uint64_t getTimestamp() const override { return std::static_pointer_cast<Avatar>(_avatar)->getLastRenderUpdateTime(); }
const AvatarSharedPointer& getAvatar() const { return _avatar; }
AvatarSharedPointer getAvatar() const { return _avatar; }
private:
AvatarSharedPointer _avatar;
};
@ -185,7 +185,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
render::Transaction transaction;
while (!sortedAvatars.empty()) {
const SortableAvatar& sortData = sortedAvatars.top();
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
const auto avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
if (ignoring) {
@ -239,7 +239,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
sortedAvatars.pop();
while (inView && !sortedAvatars.empty()) {
const SortableAvatar& newSortData = sortedAvatars.top();
const auto& newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
const auto newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
if (inView && newAvatar->hasNewJointData()) {
numAVatarsNotUpdated++;

View file

@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString
void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) {
auto wallet = DependencyManager::get<Wallet>();
QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key);
QString signature = wallet->signWithKey(text, key);
QJsonObject request;
request[propertyName] = QString(text);
if (!controlled_failure) {

View file

@ -16,9 +16,7 @@
#include "Wallet.h"
#include <AccountManager.h>
HIFI_QML_DEF(QmlCommerce)
QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
QmlCommerce::QmlCommerce() {
auto ledger = DependencyManager::get<Ledger>();
auto wallet = DependencyManager::get<Wallet>();
connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult);

View file

@ -16,16 +16,14 @@
#define hifi_QmlCommerce_h
#include <QJsonObject>
#include <OffscreenQmlDialog.h>
#include <QPixmap>
class QmlCommerce : public OffscreenQmlDialog {
class QmlCommerce : public QObject {
Q_OBJECT
HIFI_QML_DECL
public:
QmlCommerce(QQuickItem* parent = nullptr);
QmlCommerce();
signals:
void walletStatusResult(uint walletStatus);

View file

@ -548,13 +548,16 @@ QStringList Wallet::listPublicKeys() {
// the horror of code pages and so on (changing the bytes) by just returning a base64
// encoded string representing the signature (suitable for http, etc...)
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
qCInfo(commerce) << "Signing text" << text << "with key" << key;
EC_KEY* ecPrivateKey = NULL;
auto keyFilePathString = keyFilePath().toStdString();
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
unsigned int signatureBytes = 0;
qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey;
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
@ -747,12 +750,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
}
EC_KEY_free(ec);
QByteArray ba = sig.toLocal8Bit();
const char *sigChar = ba.data();
QByteArray textByteArray;
if (status > -1) {
textByteArray = QByteArray(sigChar, (int) strlen(sigChar));
textByteArray = sig.toUtf8();
}
textByteArraySize = textByteArray.size();
int certIDSize = certID.size();

View file

@ -0,0 +1,181 @@
//
// GooglePolyScriptingInterface.cpp
// interface/src/scripting
//
// Created by Elisa Lupin-Jimenez on 12/3/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QEventLoop>
#include <QtGlobal>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QString>
#include <QTime>
#include <QUrl>
#include <random>
#include "GooglePolyScriptingInterface.h"
#include "ScriptEngineLogging.h"
const QString LIST_POLY_URL = "https://poly.googleapis.com/v1/assets?";
const QString GET_POLY_URL = "https://poly.googleapis.com/v1/assets/model?";
const QStringList VALID_FORMATS = QStringList() << "BLOCKS" << "FBX" << "GLTF" << "GLTF2" << "OBJ" << "TILT" << "";
const QStringList VALID_CATEGORIES = QStringList() << "animals" << "architecture" << "art" << "food" <<
"nature" << "objects" << "people" << "scenes" << "technology" << "transport" << "";
GooglePolyScriptingInterface::GooglePolyScriptingInterface() {
// nothing to be implemented
}
void GooglePolyScriptingInterface::setAPIKey(const QString& key) {
_authCode = key;
}
QString GooglePolyScriptingInterface::getAssetList(const QString& keyword, const QString& category, const QString& format) {
QUrl url = formatURLQuery(keyword, category, format);
if (!url.isEmpty()) {
QByteArray json = parseJSON(url, 0).toJsonDocument().toJson();
return (QString) json;
} else {
qCDebug(scriptengine) << "Invalid filters were specified.";
return "";
}
}
QString GooglePolyScriptingInterface::getFBX(const QString& keyword, const QString& category) {
QUrl url = formatURLQuery(keyword, category, "FBX");
return getModelURL(url);
}
QString GooglePolyScriptingInterface::getOBJ(const QString& keyword, const QString& category) {
QUrl url = formatURLQuery(keyword, category, "OBJ");
return getModelURL(url);
}
QString GooglePolyScriptingInterface::getBlocks(const QString& keyword, const QString& category) {
QUrl url = formatURLQuery(keyword, category, "BLOCKS");
return getModelURL(url);
}
QString GooglePolyScriptingInterface::getGLTF(const QString& keyword, const QString& category) {
QUrl url = formatURLQuery(keyword, category, "GLTF");
return getModelURL(url);
}
QString GooglePolyScriptingInterface::getGLTF2(const QString& keyword, const QString& category) {
QUrl url = formatURLQuery(keyword, category, "GLTF2");
return getModelURL(url);
}
// This method will not be useful until we support Tilt models
QString GooglePolyScriptingInterface::getTilt(const QString& keyword, const QString& category) {
QUrl url = formatURLQuery(keyword, category, "TILT");
return getModelURL(url);
}
// Can provide asset name or full URL to model
QString GooglePolyScriptingInterface::getModelInfo(const QString& input) {
QString name(input);
if (input.contains("poly.googleapis") || input.contains("poly.google.com")) {
QStringList list = input.split("/");
if (input.contains("poly.googleapis")) {
name = list[4];
} else {
name = list.last();
}
}
QString urlString(GET_POLY_URL);
urlString = urlString.replace("model", name) + "key=" + _authCode;
qCDebug(scriptengine) << "Google URL request: " << urlString;
QUrl url(urlString);
QString json = parseJSON(url, 2).toString();
return json;
}
int GooglePolyScriptingInterface::getRandIntInRange(int length) {
QTime time = QTime::currentTime();
qsrand((uint)time.msec());
return qrand() % length;
}
QUrl GooglePolyScriptingInterface::formatURLQuery(const QString& keyword, const QString& category, const QString& format) {
QString queries;
if (!VALID_FORMATS.contains(format, Qt::CaseInsensitive) || !VALID_CATEGORIES.contains(category, Qt::CaseInsensitive)) {
return QUrl("");
} else {
if (!keyword.isEmpty()) {
QString keywords(keyword);
keywords.replace(" ", "+");
queries.append("&keywords=" + keywords);
}
if (!category.isEmpty()) {
queries.append("&category=" + category);
}
if (!format.isEmpty()) {
queries.append("&format=" + format);
}
QString urlString(LIST_POLY_URL + "key=" + _authCode + queries);
return QUrl(urlString);
}
}
QString GooglePolyScriptingInterface::getModelURL(const QUrl& url) {
qCDebug(scriptengine) << "Google URL request: " << url;
if (!url.isEmpty()) {
return parseJSON(url, 1).toString();
} else {
qCDebug(scriptengine) << "Invalid filters were specified.";
return "";
}
}
// FIXME: synchronous
QByteArray GooglePolyScriptingInterface::getHTTPRequest(const QUrl& url) {
QNetworkAccessManager manager;
QNetworkReply *response = manager.get(QNetworkRequest(url));
QEventLoop event;
connect(response, SIGNAL(finished()), &event, SLOT(quit()));
event.exec();
return response->readAll();
}
// 0 = asset list, 1 = model from asset list, 2 = specific model
QVariant GooglePolyScriptingInterface::parseJSON(const QUrl& url, int fileType) {
QByteArray jsonString = getHTTPRequest(url);
QJsonDocument doc = QJsonDocument::fromJson(jsonString);
QJsonObject obj = doc.object();
if (obj.isEmpty()) {
qCDebug(scriptengine) << "Assets with specified filters not found";
return "";
}
if (obj.keys().first() == "error") {
QString error = obj.value("error").toObject().value("message").toString();
qCDebug(scriptengine) << error;
return "";
}
if (fileType == 0 || fileType == 1) {
QJsonArray arr = obj.value("assets").toArray();
// return model url
if (fileType == 1) {
int random = getRandIntInRange(arr.size());
QJsonObject json = arr.at(random).toObject();
// nested JSONs
return json.value("formats").toArray().at(0).toObject().value("root").toObject().value("url");
}
// return whole asset list
return QJsonDocument(arr);
// return specific object
} else {
return jsonString;
}
}

View file

@ -0,0 +1,47 @@
//
// GooglePolyScriptingInterface.h
// interface/src/scripting
//
// Created by Elisa Lupin-Jimenez on 12/3/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_GooglePolyScriptingInterface_h
#define hifi_GooglePolyScriptingInterface_h
#include <QObject>
#include <DependencyManager.h>
class GooglePolyScriptingInterface : public QObject, public Dependency {
Q_OBJECT
public:
GooglePolyScriptingInterface();
public slots:
void setAPIKey(const QString& key);
QString getAssetList(const QString& keyword, const QString& category, const QString& format);
QString getFBX(const QString& keyword, const QString& category);
QString getOBJ(const QString& keyword, const QString& category);
QString getBlocks(const QString& keyword, const QString& categoryy);
QString getGLTF(const QString& keyword, const QString& category);
QString getGLTF2(const QString& keyword, const QString& category);
QString getTilt(const QString& keyword, const QString& category);
QString getModelInfo(const QString& input);
private:
QString _authCode;
QUrl formatURLQuery(const QString& keyword, const QString& category, const QString& format);
QString getModelURL(const QUrl& url);
QByteArray getHTTPRequest(const QUrl& url);
QVariant parseJSON(const QUrl& url, int fileType);
int getRandIntInRange(int length);
};
#endif // hifi_GooglePolyScriptingInterface_h

View file

@ -31,7 +31,7 @@
#include "scripting/HMDScriptingInterface.h"
static const QVariant TABLET_ADDRESS_DIALOG = "TabletAddressDialog.qml";
static const QVariant TABLET_ADDRESS_DIALOG = "hifi/tablet/TabletAddressDialog.qml";
template<typename T>
void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
if (!member) {
@ -91,7 +91,7 @@ void DialogsManager::setDomainConnectionFailureVisibility(bool visible) {
ConnectionFailureDialog::hide();
}
} else {
static const QUrl url("../../dialogs/TabletConnectionFailureDialog.qml");
static const QUrl url("dialogs/TabletConnectionFailureDialog.qml");
auto hmd = DependencyManager::get<HMDScriptingInterface>();
if (visible) {
tablet->initialScreen(url);

View file

@ -46,7 +46,7 @@ void LoginDialog::showWithSelection()
if (tablet->getToolbarMode()) {
LoginDialog::show();
} else {
static const QUrl url("../../dialogs/TabletLoginDialog.qml");
static const QUrl url("dialogs/TabletLoginDialog.qml");
tablet->initialScreen(url);
if (!hmd->getShouldShowTablet()) {
hmd->openTablet();

View file

@ -42,7 +42,7 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
setTransform(base3DOverlay->getTransform());
}
QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties) {
QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties, bool scalesWithParent) {
// the position and rotation in _transform are relative to the parent (aka local). The versions coming from
// scripts are in world-frame, unless localPosition or localRotation are used. Patch up the properties
// so that "position" and "rotation" are relative-to-parent values.
@ -56,7 +56,7 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert
result["position"] = result["localPosition"];
} else if (result["position"].isValid()) {
glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]),
parentID, parentJointIndex, success);
parentID, parentJointIndex, scalesWithParent, success);
if (success) {
result["position"] = vec3toVariant(localPosition);
}
@ -66,7 +66,7 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert
result["orientation"] = result["localOrientation"];
} else if (result["orientation"].isValid()) {
glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]),
parentID, parentJointIndex, success);
parentID, parentJointIndex, scalesWithParent, success);
if (success) {
result["orientation"] = quatToVariant(localOrientation);
}
@ -118,7 +118,7 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
}
}
properties = convertOverlayLocationFromScriptSemantics(properties);
properties = convertOverlayLocationFromScriptSemantics(properties, getScalesWithParent());
Overlay::setProperties(properties);
bool needRenderItemUpdate = false;
@ -335,4 +335,4 @@ SpatialParentTree* Base3DOverlay::getParentTree() const {
void Base3DOverlay::setVisible(bool visible) {
Parent::setVisible(visible);
notifyRenderVariableChange();
}
}

View file

@ -266,7 +266,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI
}
}
static const QString INSPECTION_CERTIFICATE_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
void ContextOverlayInterface::openInspectionCertificate() {
// lets open the tablet to the inspection certificate QML
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {

View file

@ -56,12 +56,12 @@ glm::vec3 Line3DOverlay::getEnd() const {
if (_endParentID != QUuid()) {
glm::vec3 localOffset = _direction * _length;
bool success;
worldEnd = localToWorld(localOffset, _endParentID, _endParentJointIndex, success);
worldEnd = localToWorld(localOffset, _endParentID, _endParentJointIndex, getScalesWithParent(), success);
return worldEnd;
}
localEnd = getLocalEnd();
worldEnd = localToWorld(localEnd, getParentID(), getParentJointIndex(), success);
worldEnd = localToWorld(localEnd, getParentID(), getParentJointIndex(), getScalesWithParent(), success);
if (!success) {
qDebug() << "Line3DOverlay::getEnd failed";
}
@ -79,10 +79,10 @@ void Line3DOverlay::setEnd(const glm::vec3& end) {
glm::vec3 offset;
if (_endParentID != QUuid()) {
offset = worldToLocal(end, _endParentID, _endParentJointIndex, success);
offset = worldToLocal(end, _endParentID, _endParentJointIndex, getScalesWithParent(), success);
} else {
localStart = getLocalStart();
localEnd = worldToLocal(end, getParentID(), getParentJointIndex(), success);
localEnd = worldToLocal(end, getParentID(), getParentJointIndex(), getScalesWithParent(), success);
offset = localEnd - localStart;
}
if (!success) {

View file

@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay()
: _model(std::make_shared<Model>(nullptr, this)),
_modelTextures(QVariantMap())
{
_model->init();
_model->setLoadingPriority(_loadPriority);
_isLoaded = false;
}
@ -38,7 +37,6 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) :
_scaleToFit(modelOverlay->_scaleToFit),
_loadPriority(modelOverlay->_loadPriority)
{
_model->init();
_model->setLoadingPriority(_loadPriority);
if (_url.isValid()) {
_updateModel = true;

View file

@ -200,7 +200,6 @@ void Web3DOverlay::setupQmlSurface() {
_webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
_webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
_webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
_webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
@ -220,9 +219,6 @@ void Web3DOverlay::setupQmlSurface() {
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
_webSurface->getSurfaceContext()->setContextProperty("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
// mark the TabletProxy object as cpp ownership.
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");

View file

@ -138,7 +138,6 @@ Avatar::~Avatar() {
void Avatar::init() {
getHead()->init();
_skeletonModel->init();
_initialized = true;
}

View file

@ -268,6 +268,7 @@ public:
virtual float getModelScale() const { return _modelScale; }
virtual void setModelScale(float scale) { _modelScale = scale; }
virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getModelScale()); }
virtual void setAvatarEntityDataChanged(bool value) override;

View file

@ -679,17 +679,13 @@ void OpenGLDisplayPlugin::internalPresent() {
void OpenGLDisplayPlugin::present() {
auto frameId = (uint64_t)presentCount();
PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId)
uint64_t startPresent = usecTimestampNow();
{
PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId)
updateFrameData();
}
incrementPresentCount();
{
PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, frameId)
_gpuContext->recycle();
}
if (_currentFrame) {
{
withPresentThreadLock([&] {
@ -718,6 +714,7 @@ void OpenGLDisplayPlugin::present() {
gpu::Backend::freeGPUMemSize.set(gpu::gl::getFreeDedicatedMemory());
}
_movingAveragePresent.addSample((float)(usecTimestampNow() - startPresent));
}
float OpenGLDisplayPlugin::newFramePresentRate() const {

View file

@ -349,7 +349,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); }
uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); }
const EntityRendererPointer& getRenderer() const { return _renderer; }
EntityRendererPointer getRenderer() const { return _renderer; }
private:
EntityRendererPointer _renderer;
};
@ -382,7 +382,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr;
size_t numSorted = sortedRenderables.size();
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
const EntityRendererPointer& renderable = sortedRenderables.top().getRenderer();
const auto renderable = sortedRenderables.top().getRenderer();
renderable->updateInScene(scene, transaction);
_renderablesToUpdate.erase(renderable->getEntity()->getID());
sortedRenderables.pop();
@ -612,7 +612,7 @@ static glm::vec2 projectOntoEntityXYPlane(EntityItemPointer entity, const PickRa
glm::vec3 entityPosition = entity->getWorldPosition();
glm::quat entityRotation = entity->getWorldOrientation();
glm::vec3 entityDimensions = entity->getDimensions();
glm::vec3 entityDimensions = entity->getScaledDimensions();
glm::vec3 entityRegistrationPoint = entity->getRegistrationPoint();
// project the intersection point onto the local xy plane of the object.

View file

@ -37,7 +37,7 @@ void LightEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
lightPayload.editBound() = render::Item::Bound();
}
glm::vec3 dimensions = entity->getDimensions();
glm::vec3 dimensions = entity->getScaledDimensions();
float largestDiameter = glm::compMax(dimensions);
light->setMaximumRadius(largestDiameter / 2.0f);

View file

@ -78,11 +78,11 @@ RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityI
RenderableModelEntityItem::~RenderableModelEntityItem() { }
void RenderableModelEntityItem::setDimensions(const glm::vec3& value) {
void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) {
glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions
if (getDimensions() != newDimensions) {
if (getUnscaledDimensions() != newDimensions) {
_dimensionsInitialized = true;
ModelEntityItem::setDimensions(value);
ModelEntityItem::setUnscaledDimensions(value);
}
}
@ -124,11 +124,11 @@ void RenderableModelEntityItem::doInitialModelSimulation() {
// translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to
// make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the
// entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getDimensions());
model->setScaleToFit(false, getScaledDimensions());
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
// now recalculate the bounds and registration
model->setScaleToFit(true, getDimensions());
model->setScaleToFit(true, getScaledDimensions());
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
model->setRotation(getWorldOrientation());
model->setTranslation(getWorldPosition());
@ -169,7 +169,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
return true;
}
if (model->getScaleToFitDimensions() != getDimensions()) {
if (model->getScaleToFitDimensions() != getScaledDimensions()) {
return true;
}
@ -209,17 +209,17 @@ void RenderableModelEntityItem::updateModelBounds() {
updateRenderItems = true;
}
if (model->getScaleToFitDimensions() != getDimensions() ||
if (model->getScaleToFitDimensions() != getScaledDimensions() ||
model->getRegistrationPoint() != getRegistrationPoint()) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards.
// This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getDimensions());
model->setScaleToFit(false, getScaledDimensions());
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
// now recalculate the bounds and registration
model->setScaleToFit(true, getDimensions());
model->setScaleToFit(true, getScaledDimensions());
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
updateRenderItems = true;
model->scaleToFit();
@ -372,7 +372,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
const uint32_t QUAD_STRIDE = 4;
ShapeType type = getShapeType();
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
auto model = getModel();
if (type == SHAPE_TYPE_COMPOUND) {
updateModelBounds();
@ -993,19 +993,15 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
}
{
// the current frame is set on the server in update() in ModelEntityItem.cpp
int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame()));
// in the case where the last frame is greater than the framecount then clamp
// it to the end of the animation until it loops around.
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
animationCurrentFrame = 0;
float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount));
if (currentFrame < 0.0f) {
currentFrame += (float)frameCount;
}
if (animationCurrentFrame == _lastKnownCurrentFrame) {
int currentIntegerFrame = (int)(glm::floor(currentFrame));
if (currentIntegerFrame == _lastKnownCurrentFrame) {
return;
}
_lastKnownCurrentFrame = animationCurrentFrame;
_lastKnownCurrentFrame = currentIntegerFrame;
}
if (_jointMapping.size() != _model->getJointStateCount()) {
@ -1157,7 +1153,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
return true;
}
if (model->getScaleToFitDimensions() != entity->getDimensions() ||
if (model->getScaleToFitDimensions() != entity->getScaledDimensions() ||
model->getRegistrationPoint() != entity->getRegistrationPoint()) {
return true;
}
@ -1213,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
model->init();
entity->setModel(model);
withWriteLock([&] { _model = model; });
}

View file

@ -60,7 +60,7 @@ public:
RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized);
virtual ~RenderableModelEntityItem();
virtual void setDimensions(const glm::vec3& value) override;
virtual void setUnscaledDimensions(const glm::vec3& value) override;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
void doInitialModelSimulation();

View file

@ -303,6 +303,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex));
#ifndef POLYLINE_ENTITY_USE_FADE_EFFECT
// glColor4f must be called after setInputFormat if it must be taken into account
if (_isFading) {
batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime));
} else {

View file

@ -213,7 +213,7 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
glm::vec3 result;
withReadLock([&] {
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units
if (isEdged(_voxelSurfaceStyle)) {
result = scale / -2.0f;
}
@ -228,7 +228,7 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
voxelVolumeSize = _voxelVolumeSize;
});
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units
bool success; // TODO -- Does this actually have to happen in world space?
glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes
@ -393,7 +393,7 @@ bool RenderablePolyVoxEntityItem::setSphere(const vec3& centerWorldCoords, float
glm::mat4 vtwMatrix = voxelToWorldMatrix();
glm::mat4 wtvMatrix = glm::inverse(vtwMatrix);
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 voxelSize = dimensions / _voxelVolumeSize;
float smallestDimensionSize = voxelSize.x;
smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y);
@ -454,7 +454,7 @@ bool RenderablePolyVoxEntityItem::setCapsule(const vec3& startWorldCoords, const
glm::mat4 vtwMatrix = voxelToWorldMatrix();
glm::mat4 wtvMatrix = glm::inverse(vtwMatrix);
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 voxelSize = dimensions / _voxelVolumeSize;
float smallestDimensionSize = voxelSize.x;
smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y);
@ -580,7 +580,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
// the PolyVox ray intersection code requires a near and far point.
// set ray cast length to long enough to cover all of the voxel space
float distanceToEntity = glm::distance(origin, getWorldPosition());
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
float largestDimension = glm::compMax(dimensions) * 2.0f;
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
@ -668,7 +668,7 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() const {
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
ShapeType shapeType = getShapeType();
if (shapeType == SHAPE_TYPE_NONE) {
info.setParams(getShapeType(), 0.5f * getDimensions());
info.setParams(getShapeType(), 0.5f * getScaledDimensions());
return;
}

View file

@ -63,7 +63,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
return true;
}
if (_dimensions != entity->getDimensions()) {
if (_dimensions != entity->getScaledDimensions()) {
return true;
}
@ -82,7 +82,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
_shape = entity->getShape();
_position = entity->getWorldPosition();
_dimensions = entity->getDimensions();
_dimensions = entity->getScaledDimensions();
_orientation = entity->getWorldOrientation();
_renderTransform = getModelTransform();
@ -137,11 +137,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
});
if (proceduralRender) {
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
geometryCache->renderWireShape(batch, geometryShape);
geometryCache->renderWireShape(batch, geometryShape, outColor);
} else {
geometryCache->renderShape(batch, geometryShape);
geometryCache->renderShape(batch, geometryShape, outColor);
}
} else {
// FIXME, support instanced multi-shape rendering using multidraw indirect

View file

@ -54,7 +54,7 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
return true;
}
if (_dimensions != entity->getDimensions()) {
if (_dimensions != entity->getScaledDimensions()) {
return true;
}
@ -67,7 +67,7 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
_textColor = toGlm(entity->getTextColorX());
_backgroundColor = toGlm(entity->getBackgroundColorX());
_dimensions = entity->getDimensions();
_dimensions = entity->getScaledDimensions();
_faceCamera = entity->getFaceCamera();
_lineHeight = entity->getLineHeight();
_text = entity->getText();

View file

@ -30,6 +30,8 @@
using namespace render;
using namespace render::entities;
static const QString WEB_ENTITY_QML = "controls/WebEntityView.qml";
const float METERS_TO_INCHES = 39.3701f;
static uint32_t _currentWebCount{ 0 };
// Don't allow more than 100 concurrent web views
@ -124,7 +126,10 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
withWriteLock([&] {
// This work must be done on the main thread
if (!hasWebSurface()) {
buildWebSurface(entity);
// If we couldn't create a new web surface, exit
if (!buildWebSurface(entity)) {
return;
}
}
if (_contextPosition != entity->getWorldPosition()) {
@ -144,7 +149,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
glm::vec2 windowSize = getWindowSize(entity);
_webSurface->resize(QSize(windowSize.x, windowSize.y));
_renderTransform = getModelTransform();
_renderTransform.postScale(entity->getDimensions());
_renderTransform.postScale(entity->getScaledDimensions());
});
}
@ -188,7 +193,6 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
});
batch.setResourceTexture(0, _texture);
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio);
DependencyManager::get<GeometryCache>()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD);
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId);
@ -218,6 +222,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
};
{
// FIXME use the surface cache instead of explicit creation
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
_webSurface->create();
}
@ -274,7 +279,7 @@ void WebEntityRenderer::destroyWebSurface() {
}
glm::vec2 WebEntityRenderer::getWindowSize(const TypedEntityPointer& entity) const {
glm::vec2 dims = glm::vec2(entity->getDimensions());
glm::vec2 dims = glm::vec2(entity->getScaledDimensions());
dims *= METERS_TO_INCHES * _lastDPI;
// ensure no side is never larger then MAX_WINDOW_SIZE
@ -291,7 +296,6 @@ void WebEntityRenderer::loadSourceURL() {
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
_lastSourceUrl.toLower().endsWith(".htm") || _lastSourceUrl.toLower().endsWith(".html")) {
_contentType = htmlContent;
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "qml/controls/"));
// We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS.
if (sourceUrl.host().endsWith("youtube.com", Qt::CaseInsensitive)) {
@ -300,12 +304,11 @@ void WebEntityRenderer::loadSourceURL() {
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
}
_webSurface->load("WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
_webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
item->setProperty("url", _lastSourceUrl);
});
} else {
_contentType = qmlContent;
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath()));
_webSurface->load(_lastSourceUrl);
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();

View file

@ -208,7 +208,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
entity->resetRenderingPropertiesChanged();
_lastPosition = entity->getWorldPosition();
_lastRotation = entity->getWorldOrientation();
_lastDimensions = entity->getDimensions();
_lastDimensions = entity->getScaledDimensions();
_keyLightProperties = entity->getKeyLightProperties();
_skyboxProperties = entity->getSkyboxProperties();
@ -280,7 +280,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
if (entity->getWorldPosition() != _lastPosition) {
return true;
}
if (entity->getDimensions() != _lastDimensions) {
if (entity->getScaledDimensions() != _lastDimensions) {
return true;
}
if (entity->getWorldOrientation() != _lastRotation) {

View file

@ -50,6 +50,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
{
setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS);
// explicitly set transform parts to set dirty flags used by batch rendering
locationChanged();
dimensionsChanged();
@ -243,7 +244,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getLocalAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getUnscaledDimensions());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity());
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity());
APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping());
@ -779,7 +780,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration);
}
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setDimensions);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setUnscaledDimensions);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, setGravity);
@ -898,7 +899,7 @@ void EntityItem::debugDump() const {
qCDebug(entities) << "EntityItem id:" << getEntityItemID();
qCDebug(entities, " edited ago:%f", (double)getEditedAgo());
qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z);
qCDebug(entities) << " dimensions:" << getDimensions();
qCDebug(entities) << " dimensions:" << getScaledDimensions();
}
// adjust any internal timestamps to fix clock skew for this server
@ -923,7 +924,7 @@ void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSk
}
float EntityItem::computeMass() const {
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
return getDensity() * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
}
@ -942,7 +943,7 @@ void EntityItem::setMass(float mass) {
// we must protect the density range to help maintain stability of physics simulation
// therefore this method might not accept the mass that is supplied.
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
// compute new density
@ -1178,7 +1179,7 @@ bool EntityItem::wantTerseEditLogging() const {
glm::mat4 EntityItem::getEntityToWorldMatrix() const {
glm::mat4 translation = glm::translate(getWorldPosition());
glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
glm::mat4 scale = glm::scale(getDimensions());
glm::mat4 scale = glm::scale(getScaledDimensions());
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
return translation * rotation * scale * registration;
}
@ -1218,7 +1219,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getUnscaledDimensions);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getLocalVelocity);
@ -1326,7 +1327,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration);
// these (along with "position" above) affect tree structure
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setUnscaledDimensions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint);
// these (along with all properties above) affect the simulation
@ -1429,7 +1430,7 @@ void EntityItem::recordCreationTime() {
const Transform EntityItem::getTransformToCenter(bool& success) const {
Transform result = getTransform(success);
if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
result.postTranslate((ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()) * getDimensions()); // Position to center
result.postTranslate((ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()) * getScaledDimensions()); // Position to center
}
return result;
}
@ -1445,7 +1446,7 @@ AACube EntityItem::getMaximumAACube(bool& success) const {
// we want to compute the furthestExtent that an entity can extend out from its "position"
// to do this we compute the max of these two vec3s: registration and 1-registration
// and then scale by dimensions
glm::vec3 maxExtents = getDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint);
glm::vec3 maxExtents = getScaledDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint);
// there exists a sphere that contains maxExtents for all rotations
float radius = glm::length(maxExtents);
@ -1470,7 +1471,7 @@ AACube EntityItem::getMinimumAACube(bool& success) const {
glm::vec3 position = getWorldPosition(success);
if (success) {
_recalcMinAACube = false;
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
@ -1500,7 +1501,7 @@ AABox EntityItem::getAABox(bool& success) const {
glm::vec3 position = getWorldPosition(success);
if (success) {
_recalcAABox = false;
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
@ -1540,12 +1541,12 @@ bool EntityItem::shouldPuffQueryAACube() const {
// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2)
// ... radius = sqrt(3 x maxDimension ^ 2) / 2.0f;
float EntityItem::getRadius() const {
return 0.5f * glm::length(getDimensions());
return 0.5f * glm::length(getScaledDimensions());
}
void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
glm::mat4 scale = glm::scale(getDimensions());
glm::mat4 scale = glm::scale(getScaledDimensions());
glm::mat4 registration = scale * glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
glm::vec3 regTransVec = glm::vec3(registration[3]); // extract position component from matrix
info.setOffset(regTransVec);
@ -1566,12 +1567,12 @@ bool EntityItem::contains(const glm::vec3& point) const {
}
void EntityItem::computeShapeInfo(ShapeInfo& info) {
info.setParams(getShapeType(), 0.5f * getDimensions());
info.setParams(getShapeType(), 0.5f * getScaledDimensions());
adjustShapeInfoByRegistration(info);
}
float EntityItem::getVolumeEstimate() const {
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
return dimensions.x * dimensions.y * dimensions.z;
}
@ -1671,11 +1672,21 @@ void EntityItem::setParentID(const QUuid& value) {
}
}
void EntityItem::setDimensions(const glm::vec3& value) {
glm::vec3 EntityItem::getScaledDimensions() const {
glm::vec3 scale = getSNScale();
return _unscaledDimensions * scale;
}
void EntityItem::setScaledDimensions(const glm::vec3& value) {
glm::vec3 parentScale = getSNScale();
setUnscaledDimensions(value * parentScale);
}
void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions
if (getDimensions() != newDimensions) {
if (getUnscaledDimensions() != newDimensions) {
withWriteLock([&] {
_dimensions = newDimensions;
_unscaledDimensions = newDimensions;
});
locationChanged();
dimensionsChanged();
@ -2071,17 +2082,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
}
EntityDynamicPointer action = _objectActions[actionID];
action->setOwnerEntity(nullptr);
action->setIsMine(false);
if (simulation) {
action->removeFromSimulation(simulation);
}
bool success = true;
serializeActions(success, _allActionsDataCache);
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
auto removedActionType = action->getType();
if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) {
_dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING;
@ -2098,7 +2098,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
// because they should have been set correctly when the action was added
// and/or when children were linked
}
action->setOwnerEntity(nullptr);
action->setIsMine(false);
_objectActions.remove(actionID);
if (simulation) {
action->removeFromSimulation(simulation);
}
bool success = true;
serializeActions(success, _allActionsDataCache);
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
setDynamicDataNeedsTransmit(true);
return success;
}
@ -2366,6 +2376,16 @@ void EntityItem::dimensionsChanged() {
somethingChangedNotification();
}
bool EntityItem::getScalesWithParent() const {
// keep this logic the same as in EntityItemProperties::getScalesWithParent
if (getClientOnly()) {
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
return !ancestorID.isNull();
} else {
return false;
}
}
void EntityItem::globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate, const glm::vec3& offset) const {
// TODO -- combine this with convertLocationToScriptSemantics
bool success;
@ -2373,7 +2393,7 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt
if (success) {
properties.setPosition(globalPosition + offset);
properties.setRotation(getWorldOrientation());
properties.setDimensions(getDimensions());
properties.setDimensions(getScaledDimensions());
// Should we do velocities and accelerations, too? This could end up being quite involved, which is why the method exists.
} else {
properties.setPosition(getQueryAACube().calcCenter() + offset); // best we can do

View file

@ -180,8 +180,11 @@ public:
void setDescription(const QString& value);
/// Dimensions in meters (0.0 - TREE_SCALE)
inline const glm::vec3 getDimensions() const { return _dimensions; }
virtual void setDimensions(const glm::vec3& value);
glm::vec3 getScaledDimensions() const;
virtual void setScaledDimensions(const glm::vec3& value);
inline const glm::vec3 getUnscaledDimensions() const { return _unscaledDimensions; }
virtual void setUnscaledDimensions(const glm::vec3& value);
float getLocalRenderAlpha() const;
void setLocalRenderAlpha(float localRenderAlpha);
@ -456,6 +459,8 @@ public:
virtual void locationChanged(bool tellPhysics = true) override;
virtual bool getScalesWithParent() const override;
using ChangeHandlerCallback = std::function<void(const EntityItemID&)>;
using ChangeHandlerId = QUuid;
ChangeHandlerId registerChangeHandler(const ChangeHandlerCallback& handler);
@ -477,7 +482,7 @@ protected:
virtual void dimensionsChanged() override;
glm::vec3 _dimensions { ENTITY_ITEM_DEFAULT_DIMENSIONS };
glm::vec3 _unscaledDimensions { ENTITY_ITEM_DEFAULT_DIMENSIONS };
EntityTypes::EntityType _type { EntityTypes::Unknown };
quint64 _lastSimulated { 0 }; // last time this entity called simulate(), this includes velocity, angular velocity,
// and physics changes

View file

@ -365,6 +365,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_VELOCITY, localVelocity);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_DIMENSIONS, localDimensions);
CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed);
CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
@ -628,6 +629,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_VELOCITY, localVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_DIMENSIONS, localDimensions);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID);
@ -805,6 +807,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localVelocity, glmVec3, setLocalVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localAngularVelocity, glmVec3, setLocalAngularVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localDimensions, glmVec3, setLocalDimensions);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations);
@ -953,6 +956,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(localRotation);
COPY_PROPERTY_IF_CHANGED(localVelocity);
COPY_PROPERTY_IF_CHANGED(localAngularVelocity);
COPY_PROPERTY_IF_CHANGED(localDimensions);
COPY_PROPERTY_IF_CHANGED(jointRotationsSet);
COPY_PROPERTY_IF_CHANGED(jointRotations);
@ -1132,6 +1136,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glm::quat);
ADD_PROPERTY_TO_MAP(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>);
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>);
@ -2470,9 +2475,25 @@ bool EntityItemProperties::transformChanged() const {
localPositionChanged() || localRotationChanged();
}
bool EntityItemProperties::getScalesWithParent() const {
// keep this logic the same as in EntityItem::getScalesWithParent
bool scalesWithParent { false };
if (parentIDChanged()) {
bool success;
SpatiallyNestablePointer parent = SpatiallyNestable::findByID(getParentID(), success);
if (success && parent) {
bool avatarAncestor = (parent->getNestableType() == NestableType::Avatar ||
parent->hasAncestorOfType(NestableType::Avatar));
scalesWithParent = getClientOnly() && avatarAncestor;
}
}
return scalesWithParent;
}
bool EntityItemProperties::parentRelatedPropertyChanged() const {
return positionChanged() || rotationChanged() ||
localPositionChanged() || localRotationChanged() ||
localDimensionsChanged() ||
parentIDChanged() || parentJointIndexChanged();
}
@ -2530,7 +2551,8 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
return false;
}
const unsigned char* key = reinterpret_cast<const unsigned char*>(publicKey.toUtf8().constData());
auto keyByteArray = publicKey.toUtf8();
auto key = keyByteArray.constData();
int keyLength = publicKey.length();
BIO *bio = BIO_new_mem_buf((void*)key, keyLength);
@ -2548,19 +2570,23 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
// ECSDA verification prototype: note that type is currently ignored
// int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen,
// const unsigned char *sig, int siglen, EC_KEY *eckey);
bool answer = ECDSA_verify(0,
int answer = ECDSA_verify(0,
digest,
digestLength,
signature,
signatureLength,
ec);
long error = ERR_get_error();
if (error != 0) {
const char* error_str = ERR_error_string(error, NULL);
qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str
if (error != 0 || answer == -1) {
qCWarning(entities) << "ERROR while verifying signature!"
<< "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength
<< "\nDigest:" << digest << "\nDigest Length:" << digestLength
<< "\nSignature:" << signature << "\nSignature Length:" << signatureLength;
while (error != 0) {
const char* error_str = ERR_error_string(error, NULL);
qCWarning(entities) << "EC error:" << error_str;
error = ERR_get_error();
}
}
EC_KEY_free(ec);
if (bio) {
@ -2569,7 +2595,7 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
if (evp_key) {
EVP_PKEY_free(evp_key);
}
return answer;
return (answer == 1);
} else {
if (bio) {
BIO_free(bio);

View file

@ -88,6 +88,7 @@ public:
EntityPropertyFlags getChangedProperties() const;
bool transformChanged() const;
bool getScalesWithParent() const;
bool parentRelatedPropertyChanged() const;
bool queryAACubeRelatedPropertyChanged() const;
@ -227,6 +228,7 @@ public:
DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION);
DEFINE_PROPERTY_REF(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3);
DEFINE_PROPERTY_REF(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3);
DEFINE_PROPERTY_REF(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, glmVec3, ENTITY_ITEM_ZERO_VEC3);
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>, QVector<bool>());
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>, QVector<glm::quat>());

View file

@ -220,6 +220,8 @@ enum EntityPropertyList {
PROP_HAZE_KEYLIGHT_RANGE,
PROP_HAZE_KEYLIGHT_ALTITUDE,
PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -117,7 +117,8 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
}
}
EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties& entitySideProperties) {
EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperties& entitySideProperties,
bool scalesWithParent) {
// In EntityTree code, properties.position and properties.rotation are relative to the parent. In javascript,
// they are in world-space. The local versions are put into localPosition and localRotation and position and
// rotation are converted from local to world space.
@ -126,35 +127,48 @@ EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties
scriptSideProperties.setLocalRotation(entitySideProperties.getRotation());
scriptSideProperties.setLocalVelocity(entitySideProperties.getLocalVelocity());
scriptSideProperties.setLocalAngularVelocity(entitySideProperties.getLocalAngularVelocity());
scriptSideProperties.setLocalDimensions(entitySideProperties.getDimensions());
bool success;
glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
scalesWithParent,
success);
glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
scalesWithParent,
success);
glm::vec3 worldVelocity = SpatiallyNestable::localToWorldVelocity(entitySideProperties.getVelocity(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
scalesWithParent,
success);
glm::vec3 worldAngularVelocity = SpatiallyNestable::localToWorldAngularVelocity(entitySideProperties.getAngularVelocity(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
scalesWithParent,
success);
glm::vec3 worldDimensions = SpatiallyNestable::localToWorldDimensions(entitySideProperties.getDimensions(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
scalesWithParent,
success);
scriptSideProperties.setPosition(worldPosition);
scriptSideProperties.setRotation(worldRotation);
scriptSideProperties.setVelocity(worldVelocity);
scriptSideProperties.setAngularVelocity(worldAngularVelocity);
scriptSideProperties.setDimensions(worldDimensions);
return scriptSideProperties;
}
EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperties& scriptSideProperties) {
EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties,
bool scalesWithParent) {
// convert position and rotation properties from world-space to local, unless localPosition and localRotation
// are set. If they are set, they overwrite position and rotation.
EntityItemProperties entitySideProperties = scriptSideProperties;
@ -168,7 +182,7 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
success);
scalesWithParent, success);
entitySideProperties.setPosition(localPosition);
}
@ -178,7 +192,7 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
success);
scalesWithParent, success);
entitySideProperties.setRotation(localRotation);
}
@ -188,7 +202,7 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
glm::vec3 localVelocity = SpatiallyNestable::worldToLocalVelocity(entitySideProperties.getVelocity(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
success);
scalesWithParent, success);
entitySideProperties.setVelocity(localVelocity);
}
@ -199,10 +213,20 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
SpatiallyNestable::worldToLocalAngularVelocity(entitySideProperties.getAngularVelocity(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
success);
scalesWithParent, success);
entitySideProperties.setAngularVelocity(localAngularVelocity);
}
if (scriptSideProperties.localDimensionsChanged()) {
entitySideProperties.setDimensions(scriptSideProperties.getLocalDimensions());
} else if (scriptSideProperties.dimensionsChanged()) {
glm::vec3 localDimensions = SpatiallyNestable::worldToLocalDimensions(entitySideProperties.getDimensions(),
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
scalesWithParent, success);
entitySideProperties.setDimensions(localDimensions);
}
return entitySideProperties;
}
@ -212,9 +236,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
_activityTracking.addedEntityCount++;
EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties);
propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged());
EntityItemProperties propertiesWithSimID = properties;
if (clientOnly) {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID();
@ -222,6 +244,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
propertiesWithSimID.setOwningAvatarID(myNodeID);
}
bool scalesWithParent = propertiesWithSimID.getScalesWithParent();
propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent);
propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged());
auto dimensions = propertiesWithSimID.getDimensions();
float volume = dimensions.x * dimensions.y * dimensions.z;
auto density = propertiesWithSimID.getDensity();
@ -295,15 +322,20 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__);
bool scalesWithParent { false };
EntityItemProperties results;
if (_entityTree) {
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));
if (entity) {
scalesWithParent = entity->getScalesWithParent();
if (desiredProperties.getHasProperty(PROP_POSITION) ||
desiredProperties.getHasProperty(PROP_ROTATION) ||
desiredProperties.getHasProperty(PROP_LOCAL_POSITION) ||
desiredProperties.getHasProperty(PROP_LOCAL_ROTATION)) {
desiredProperties.getHasProperty(PROP_LOCAL_ROTATION) ||
desiredProperties.getHasProperty(PROP_LOCAL_VELOCITY) ||
desiredProperties.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) ||
desiredProperties.getHasProperty(PROP_LOCAL_DIMENSIONS)) {
// if we are explicitly getting position or rotation, we need parent information to make sense of them.
desiredProperties.setHasProperty(PROP_PARENT_ID);
desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX);
@ -316,6 +348,9 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
desiredProperties = entity->getEntityProperties(params);
desiredProperties.setHasProperty(PROP_LOCAL_POSITION);
desiredProperties.setHasProperty(PROP_LOCAL_ROTATION);
desiredProperties.setHasProperty(PROP_LOCAL_VELOCITY);
desiredProperties.setHasProperty(PROP_LOCAL_ANGULAR_VELOCITY);
desiredProperties.setHasProperty(PROP_LOCAL_DIMENSIONS);
}
results = entity->getProperties(desiredProperties);
@ -323,7 +358,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
});
}
return convertLocationToScriptSemantics(results);
return convertPropertiesToScriptSemantics(results, scalesWithParent);
}
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
@ -390,10 +425,13 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) {
properties.setRotation(entity->getWorldOrientation());
}
if (!scriptSideProperties.localDimensionsChanged() && !scriptSideProperties.dimensionsChanged()) {
properties.setDimensions(entity->getScaledDimensions());
}
}
properties = convertLocationFromScriptSemantics(properties);
properties.setClientOnly(entity->getClientOnly());
properties.setOwningAvatarID(entity->getOwningAvatarID());
properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent());
float cost = calculateCost(density * volume, oldVelocity, newVelocity);
cost *= costMultiplier;
@ -529,7 +567,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
return;
}
auto dimensions = entity->getDimensions();
auto dimensions = entity->getScaledDimensions();
float volume = dimensions.x * dimensions.y * dimensions.z;
auto density = entity->getDensity();
auto velocity = entity->getWorldVelocity().length();

View file

@ -1189,13 +1189,15 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity
key = sent.second;
}
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----";
bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8());
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n";
QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256);
bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8()));
if (verificationSuccess) {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded.";
} else {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce;
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed. Actual nonce:" << actualNonce <<
"\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key;
}
return verificationSuccess;

View file

@ -667,7 +667,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 dimensions = entity->getDimensions();
glm::vec3 dimensions = entity->getScaledDimensions();
glm::vec3 registrationPoint = entity->getRegistrationPoint();
glm::vec3 corner = -(dimensions * registrationPoint);
@ -763,7 +763,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
glm::vec3 penetration;
if (!success || entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
glm::vec3 dimensions = entity->getDimensions();
glm::vec3 dimensions = entity->getScaledDimensions();
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to

View file

@ -41,16 +41,16 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem(
_color[RED_INDEX] = _color[GREEN_INDEX] = _color[BLUE_INDEX] = 0;
}
void LightEntityItem::setDimensions(const glm::vec3& value) {
void LightEntityItem::setUnscaledDimensions(const glm::vec3& value) {
if (_isSpotlight) {
// If we are a spotlight, treat the z value as our radius or length, and
// recalculate the x/y dimensions to properly encapsulate the spotlight.
const float length = value.z;
const float width = length * glm::sin(glm::radians(_cutoff));
EntityItem::setDimensions(glm::vec3(width, width, length));
EntityItem::setUnscaledDimensions(glm::vec3(width, width, length));
} else {
float maxDimension = glm::compMax(value);
EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
EntityItem::setUnscaledDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
}
}
@ -98,7 +98,7 @@ void LightEntityItem::setIsSpotlight(bool value) {
return;
}
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 newDimensions;
if (value) {
const float length = dimensions.z;
@ -112,7 +112,7 @@ void LightEntityItem::setIsSpotlight(bool value) {
_isSpotlight = value;
_lightPropertiesChanged = true;
});
setDimensions(newDimensions);
setScaledDimensions(newDimensions);
}
void LightEntityItem::setCutoff(float value) {
@ -128,9 +128,9 @@ void LightEntityItem::setCutoff(float value) {
if (getIsSpotlight()) {
// If we are a spotlight, adjusting the cutoff will affect the area we encapsulate,
// so update the dimensions to reflect this.
const float length = getDimensions().z;
const float length = getScaledDimensions().z;
const float width = length * glm::sin(glm::radians(_cutoff));
setDimensions(glm::vec3(width, width, length));
setScaledDimensions(glm::vec3(width, width, length));
}
withWriteLock([&] {

View file

@ -29,7 +29,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
virtual void setDimensions(const glm::vec3& value) override;
virtual void setUnscaledDimensions(const glm::vec3& value) override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual bool setSubClassProperties(const EntityItemProperties& properties) override;

View file

@ -80,7 +80,7 @@ bool LineEntityItem::appendPoint(const glm::vec3& point) {
qCDebug(entities) << "MAX POINTS REACHED!";
return false;
}
glm::vec3 halfBox = getDimensions() * 0.5f;
glm::vec3 halfBox = getScaledDimensions() * 0.5f;
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
qCDebug(entities) << "Point is outside entity's bounding box";
return false;
@ -96,7 +96,7 @@ bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
if (points.size() > MAX_POINTS_PER_LINE) {
return false;
}
glm::vec3 halfBox = getDimensions() * 0.5f;
glm::vec3 halfBox = getScaledDimensions() * 0.5f;
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
@ -157,7 +157,7 @@ void LineEntityItem::debugDump() const {
qCDebug(entities) << " LINE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}

View file

@ -245,7 +245,7 @@ void ModelEntityItem::updateFrameCount() {
if (_currentFrame < 0.0f) {
return;
}
if (!_lastAnimated) {
_lastAnimated = usecTimestampNow();
return;
@ -263,7 +263,7 @@ void ModelEntityItem::updateFrameCount() {
}
int updatedFrameCount = getAnimationLastFrame() - getAnimationFirstFrame() + 1;
if (!getAnimationHold() && getAnimationIsPlaying()) {
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
_currentFrame += (deltaTime * getAnimationFPS());
@ -283,15 +283,13 @@ void ModelEntityItem::updateFrameCount() {
// qCDebug(entities) << "in update frame " << _currentFrame;
setAnimationCurrentFrame(_currentFrame);
}
}
void ModelEntityItem::debugDump() const {
qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID();
qCDebug(entities) << " edited ago:" << getEditedAgo();
qCDebug(entities) << " position:" << getWorldPosition();
qCDebug(entities) << " dimensions:" << getDimensions();
qCDebug(entities) << " dimensions:" << getScaledDimensions();
qCDebug(entities) << " model URL:" << getModelURL();
qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL();
}

View file

@ -353,7 +353,7 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() {
float maxDistanceValue = glm::compMax(maxDistance);
//times 2 because dimensions are diameters not radii
glm::vec3 dims(2.0f * maxDistanceValue);
EntityItem::setDimensions(dims);
EntityItem::setScaledDimensions(dims);
}
@ -593,7 +593,7 @@ void ParticleEffectEntityItem::debugDump() const {
_particleProperties.color.gradient.target.green << "," <<
_particleProperties.color.gradient.target.blue;
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}

View file

@ -191,7 +191,7 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() {
}
// if Polyline has only one or fewer points, use default dimension settings
setDimensions(newScale);
setScaledDimensions(newScale);
EntityItem::setRegistrationPoint(newRegistrationPoint);
}
@ -257,7 +257,7 @@ void PolyLineEntityItem::debugDump() const {
qCDebug(entities) << " QUAD EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}

View file

@ -229,7 +229,7 @@ void PolyVoxEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}
@ -377,7 +377,7 @@ EntityItemID PolyVoxEntityItem::getZPNeighborID() const {
glm::vec3 PolyVoxEntityItem::getSurfacePositionAdjustment() const {
glm::vec3 result;
withReadLock([&] {
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units
if (isEdged()) {
result = scale / -2.0f;
}
@ -392,7 +392,7 @@ glm::mat4 PolyVoxEntityItem::voxelToLocalMatrix() const {
voxelVolumeSize = _voxelVolumeSize;
});
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units
bool success; // TODO -- Does this actually have to happen in world space?
glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes

View file

@ -106,11 +106,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) {
break;
case entity::Shape::Circle:
// Circle is implicitly flat so we enforce flat dimensions
setDimensions(getDimensions());
setUnscaledDimensions(getUnscaledDimensions());
break;
case entity::Shape::Quad:
// Quad is implicitly flat so we enforce flat dimensions
setDimensions(getDimensions());
setUnscaledDimensions(getUnscaledDimensions());
break;
default:
_type = EntityTypes::Shape;
@ -204,15 +204,15 @@ void ShapeEntityItem::setColor(const QColor& value) {
setAlpha(value.alpha());
}
void ShapeEntityItem::setDimensions(const glm::vec3& value) {
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
const float MAX_FLAT_DIMENSION = 0.0001f;
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
// enforce flatness in Y
glm::vec3 newDimensions = value;
newDimensions.y = MAX_FLAT_DIMENSION;
EntityItem::setDimensions(newDimensions);
} else {
EntityItem::setDimensions(value);
EntityItem::setUnscaledDimensions(newDimensions);
} else {
EntityItem::setUnscaledDimensions(value);
}
}
@ -256,7 +256,7 @@ void ShapeEntityItem::debugDump() const {
qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType());
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
}
@ -266,7 +266,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
// This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc)
// is set.
const glm::vec3 entityDimensions = getDimensions();
const glm::vec3 entityDimensions = getScaledDimensions();
switch (_shape){
case entity::Shape::Quad:

View file

@ -80,7 +80,7 @@ public:
const rgbColor& getColor() const { return _color; }
void setColor(const rgbColor& value);
void setDimensions(const glm::vec3& value) override;
void setUnscaledDimensions(const glm::vec3& value) override;
xColor getXColor() const;
void setColor(const xColor& value);

View file

@ -41,9 +41,9 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en
const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f;
void TextEntityItem::setDimensions(const glm::vec3& value) {
void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) {
// NOTE: Text Entities always have a "depth" of 1cm.
EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH));
EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH));
}
EntityItemProperties TextEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
@ -132,7 +132,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
bool& keepSearching, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
void** intersectedObject, bool precisionPicking) const {
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation *

View file

@ -23,7 +23,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
virtual void setDimensions(const glm::vec3& value) override;
virtual void setUnscaledDimensions(const glm::vec3& value) override;
virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity

View file

@ -36,9 +36,9 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(enti
const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f;
void WebEntityItem::setDimensions(const glm::vec3& value) {
void WebEntityItem::setUnscaledDimensions(const glm::vec3& value) {
// NOTE: Web Entities always have a "depth" of 1cm.
EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH));
EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH));
}
EntityItemProperties WebEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
@ -109,7 +109,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g
bool& keepSearching, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
void** intersectedObject, bool precisionPicking) const {
glm::vec3 dimensions = getDimensions();
glm::vec3 dimensions = getScaledDimensions();
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));

View file

@ -22,7 +22,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
virtual void setDimensions(const glm::vec3& value) override;
virtual void setUnscaledDimensions(const glm::vec3& value) override;
virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity

View file

@ -242,7 +242,7 @@ void ZoneEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " _backgroundMode:" << EntityItemProperties::getBackgroundModeString(_backgroundMode);
qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getHazeModeString(_hazeMode);

View file

@ -605,6 +605,10 @@ void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) {
if (_input._colorAttribute != newColor) {
_input._colorAttribute = newColor;
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
// Color has been changed and is not white. To prevent colors from bleeding
// between different objects, we need to set the _hadColorAttribute flag
// as if a previous render call had potential colors
_input._hadColorAttribute = (newColor != glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
}
(void)CHECK_GL_ERROR();
}
@ -772,7 +776,7 @@ void GLBackend::recycle() const {
GLVariableAllocationSupport::manageMemory();
GLVariableAllocationSupport::_frameTexturesCreated = 0;
Texture::KtxStorage::releaseOpenKtxFiles();
}
void GLBackend::setCameraCorrection(const Mat4& correction) {

View file

@ -253,6 +253,7 @@ protected:
struct InputStageState {
bool _invalidFormat { true };
bool _hadColorAttribute{ true };
Stream::FormatPointer _format;
std::string _formatKey;

View file

@ -62,6 +62,8 @@ void GL41Backend::updateInput() {
// now we need to bind the buffers and assign the attrib pointers
if (_input._format) {
bool hasColorAttribute{ false };
const Buffers& buffers = _input._buffers;
const Offsets& offsets = _input._bufferOffsets;
const Offsets& strides = _input._bufferStrides;
@ -98,6 +100,8 @@ void GL41Backend::updateInput() {
uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]);
GLboolean isNormalized = attrib._element.isNormalized();
hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
if (attrib._element.isInteger()) {
glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride,
@ -117,6 +121,15 @@ void GL41Backend::updateInput() {
}
}
}
if (_input._hadColorAttribute && !hasColorAttribute) {
// The previous input stage had a color attribute but this one doesn't so reset
// color to pure white.
const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
glVertexAttrib4fv(Stream::COLOR, &white.r);
_input._colorAttribute = white;
}
_input._hadColorAttribute = hasColorAttribute;
}
// everything format related should be in sync now
_input._invalidFormat = false;

View file

@ -32,6 +32,8 @@ void GL45Backend::updateInput() {
// Assign the vertex format required
if (_input._format) {
bool hasColorAttribute{ false };
_input._attribBindingBuffers.reset();
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
@ -54,6 +56,9 @@ void GL45Backend::updateInput() {
GLboolean isNormalized = attrib._element.isNormalized();
GLenum perLocationSize = attrib._element.getLocationSize();
hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
GLuint attriNum = (GLuint)(slot + locNum);
newActivation.set(attriNum);
@ -84,6 +89,15 @@ void GL45Backend::updateInput() {
glVertexBindingDivisor(bufferChannelNum, frequency);
#endif
}
if (_input._hadColorAttribute && !hasColorAttribute) {
// The previous input stage had a color attribute but this one doesn't so reset
// color to pure white.
const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
glVertexAttrib4fv(Stream::COLOR, &white.r);
_input._colorAttribute = white;
}
_input._hadColorAttribute = hasColorAttribute;
}
// Manage Activation what was and what is expected now

View file

@ -321,13 +321,18 @@ public:
void reset() override { }
// Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle)
static void releaseOpenKtxFiles();
protected:
std::shared_ptr<storage::FileStorage> maybeOpenFile() const;
mutable std::mutex _cacheFileCreateMutex;
mutable std::mutex _cacheFileWriteMutex;
mutable std::shared_ptr<std::mutex> _cacheFileMutex { std::make_shared<std::mutex>() };
mutable std::weak_ptr<storage::FileStorage> _cacheFile;
static std::vector<std::pair<std::shared_ptr<storage::FileStorage>, std::shared_ptr<std::mutex>>> _cachedKtxFiles;
static std::mutex _cachedKtxFilesMutex;
std::string _filename;
cache::FilePointer _cacheEntry;
std::atomic<uint8_t> _minMipLevelAvailable;

View file

@ -23,6 +23,9 @@ using namespace gpu;
using PixelsPointer = Texture::PixelsPointer;
using KtxStorage = Texture::KtxStorage;
std::vector<std::pair<std::shared_ptr<storage::FileStorage>, std::shared_ptr<std::mutex>>> KtxStorage::_cachedKtxFiles;
std::mutex KtxStorage::_cachedKtxFilesMutex;
struct GPUKTXPayload {
using Version = uint8;
@ -187,36 +190,44 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
}
}
// maybeOpenFile should be called with _cacheFileMutex already held to avoid modifying the file from multiple threads
std::shared_ptr<storage::FileStorage> KtxStorage::maybeOpenFile() const {
// 1. Try to get the shared ptr
// 2. If it doesn't exist, grab the mutex around its creation
// 3. If it was created before we got the mutex, return it
// 4. Otherwise, create it
// Try to get the shared_ptr
std::shared_ptr<storage::FileStorage> file = _cacheFile.lock();
if (file) {
return file;
}
// If the file isn't open, create it and save a weak_ptr to it
file = std::make_shared<storage::FileStorage>(_filename.c_str());
_cacheFile = file;
{
std::lock_guard<std::mutex> lock{ _cacheFileCreateMutex };
file = _cacheFile.lock();
if (file) {
return file;
}
file = std::make_shared<storage::FileStorage>(_filename.c_str());
_cacheFile = file;
// Add the shared_ptr to the global list of open KTX files, to be released at the beginning of the next present thread frame
std::lock_guard<std::mutex> lock(_cachedKtxFilesMutex);
_cachedKtxFiles.emplace_back(file, _cacheFileMutex);
}
return file;
}
void KtxStorage::releaseOpenKtxFiles() {
std::vector<std::pair<std::shared_ptr<storage::FileStorage>, std::shared_ptr<std::mutex>>> localKtxFiles;
{
std::lock_guard<std::mutex> lock(_cachedKtxFilesMutex);
localKtxFiles.swap(_cachedKtxFiles);
}
for (auto& cacheFileAndMutex : localKtxFiles) {
std::lock_guard<std::mutex> lock(*(cacheFileAndMutex.second));
cacheFileAndMutex.first.reset();
}
}
PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face);
auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face);
if (faceSize != 0 && faceOffset != 0) {
std::lock_guard<std::mutex> lock(*_cacheFileMutex);
auto file = maybeOpenFile();
if (file) {
auto storageView = file->createView(faceSize, faceOffset);
@ -262,6 +273,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
return;
}
std::lock_guard<std::mutex> lock(*_cacheFileMutex);
auto file = maybeOpenFile();
if (!file) {
qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename);
@ -279,8 +291,6 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
imageData += ktx::IMAGE_SIZE_WIDTH;
{
std::lock_guard<std::mutex> lock { _cacheFileWriteMutex };
if (level != _minMipLevelAvailable - 1) {
qWarning() << "Invalid level to be stored";
return;

Some files were not shown because too many files have changed in this diff Show more