mirror of
https://github.com/lubosz/overte.git
synced 2025-08-29 07:16:59 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into oldPropsFilters
This commit is contained in:
commit
f639e950e9
164 changed files with 2239 additions and 1639 deletions
27
BUILD_LINUX_CHEATSHEET.md
Normal file
27
BUILD_LINUX_CHEATSHEET.md
Normal 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
|
|
@ -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--;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
18
interface/resources/qml/OverlayWindowTest.qml
Normal file
18
interface/resources/qml/OverlayWindowTest.qml
Normal 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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -30,8 +30,8 @@ Item {
|
|||
source: "images/wallet-bg.jpg";
|
||||
}
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
Connections {
|
||||
target: Commerce;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ Item {
|
|||
id: root;
|
||||
property bool justSubmitted: false;
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
Connections {
|
||||
target: Commerce;
|
||||
|
||||
onSecurityImageResult: {
|
||||
securityImageChangePageSecurityImage.source = "";
|
||||
|
|
|
@ -25,8 +25,8 @@ Item {
|
|||
|
||||
id: root;
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
Connections {
|
||||
target: Commerce;
|
||||
}
|
||||
|
||||
// "Unavailable"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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";
|
||||
|
|
159
interface/resources/qml/hifi/tablet/TabletHome.qml
Normal file
159
interface/resources/qml/hifi/tablet/TabletHome.qml
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
181
interface/src/scripting/GooglePolyScriptingInterface.cpp
Normal file
181
interface/src/scripting/GooglePolyScriptingInterface.cpp
Normal 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;
|
||||
}
|
||||
}
|
47
interface/src/scripting/GooglePolyScriptingInterface.h
Normal file
47
interface/src/scripting/GooglePolyScriptingInterface.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -138,7 +138,6 @@ Avatar::~Avatar() {
|
|||
|
||||
void Avatar::init() {
|
||||
getHead()->init();
|
||||
_skeletonModel->init();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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; });
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([&] {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -253,6 +253,7 @@ protected:
|
|||
|
||||
struct InputStageState {
|
||||
bool _invalidFormat { true };
|
||||
bool _hadColorAttribute{ true };
|
||||
Stream::FormatPointer _format;
|
||||
std::string _formatKey;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue