Merge branch 'master' of github.com:highfidelity/hifi into W-21204-tetherball-toy

This commit is contained in:
Rob Kayson 2017-04-07 19:26:02 -07:00
commit 5ce70decfc
157 changed files with 3810 additions and 1829 deletions

View file

@ -17,6 +17,8 @@ Documentation
=========
Documentation is available at [docs.highfidelity.com](https://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project).
There is also detailed [documentation on our coding standards](https://wiki.highfidelity.com/wiki/Coding_Standards).
Build Instructions
=========
All information required to build is found in the [build guide](BUILD.md).

View file

@ -336,6 +336,10 @@ void Agent::executeScript() {
// call model URL setters with empty URLs so our avatar, if user, will have the default models
scriptedAvatar->setSkeletonModelURL(QUrl());
// force lazy initialization of the head data for the scripted avatar
// since it is referenced below by computeLoudness and getAudioLoudness
scriptedAvatar->getHeadOrientation();
// give this AvatarData object to the script engine
_scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data());

View file

@ -7,8 +7,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/ValveSoftware/openvr/archive/v1.0.3.zip
URL_MD5 b484b12901917cc739e40389583c8b0d
URL https://github.com/ValveSoftware/openvr/archive/v1.0.6.zip
URL_MD5 f6892cd3a3078f505d03b4297f5a1951
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""

View file

@ -2,6 +2,8 @@
"name": "Kinect to Standard",
"channels": [
{ "from": "Kinect.LeftHand", "to": "Standard.LeftHand" },
{ "from": "Kinect.RightHand", "to": "Standard.RightHand" }
{ "from": "Kinect.RightHand", "to": "Standard.RightHand" },
{ "from": "Kinect.LeftFoot", "to": "Standard.LeftFoot" },
{ "from": "Kinect.RightFoot", "to": "Standard.RightFoot" }
]
}

View file

@ -58,6 +58,9 @@
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
{ "from": "Standard.LeftHand", "to": "Actions.LeftHand" },
{ "from": "Standard.RightHand", "to": "Actions.RightHand" }
{ "from": "Standard.RightHand", "to": "Actions.RightHand" },
{ "from": "Standard.LeftFoot", "to": "Actions.LeftFoot" },
{ "from": "Standard.RightFoot", "to": "Actions.RightFoot" }
]
}

0
interface/resources/fonts/hifi-glyphs.ttf Executable file → Normal file
View file

View file

@ -2,6 +2,7 @@ import QtQuick 2.5
import QtQuick.Controls 1.2
import QtWebChannel 1.0
import QtWebEngine 1.2
import FileTypeProfile 1.0
import "controls-uit"
import "styles" as HifiStyles
@ -216,6 +217,11 @@ ScrollingWindow {
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
profile: FileTypeProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
webChannel.registeredObjects: [eventBridgeWrapper]

View file

@ -1,5 +1,5 @@
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Controls 1.4
import QtWebChannel 1.0
import QtWebEngine 1.2
@ -7,7 +7,7 @@ import "controls"
import "styles" as HifiStyles
import "styles-uit"
import "windows"
import HFWebEngineProfile 1.0
import HFTabletWebEngineProfile 1.0
Item {
id: root
@ -27,150 +27,103 @@ Item {
x: 0
y: 0
function goBack() {
webview.goBack();
}
function goForward() {
webview.goForward();
}
function gotoPage(url) {
webview.url = url;
}
function setProfile(profile) {
webview.profile = profile;
}
function reloadPage() {
webview.reloadAndBypassCache();
webview.setActiveFocusOnPress(true);
webview.setEnabled(true);
QtObject {
id: eventBridgeWrapper
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
Item {
id:item
WebEngineView {
id: webview
objectName: "webEngineView"
x: 0
y: 0
width: parent.width
implicitHeight: parent.height
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
QtObject {
id: eventBridgeWrapper
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
profile: HFTabletWebEngineProfile {
id: webviewTabletProfile
storageName: "qmlTabletWebEngine"
}
WebEngineView {
id: webview
objectName: "webEngineView"
x: 0
y: 0
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
property string userScriptUrl: ""
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
webChannel.registeredObjects: [eventBridgeWrapper]
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
Component.onCompleted: {
// Ensure the JS from the web-engine makes it to our logging
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("TabletBrowser");
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
webview.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface";
web.address = url;
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
onLoadingChanged: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
webChannel.registeredObjects: [eventBridgeWrapper]
Component.onCompleted: {
// Ensure the JS from the web-engine makes it to our logging
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
web.address = url;
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
onActiveFocusOnPressChanged: {
console.log("on active focus changed");
setActiveFocusOnPress(true);
}
onNewViewRequested:{
// desktop is not defined for web-entities
if (stackRoot.isDesktop) {
var component = Qt.createComponent("./Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
} else {
var component = Qt.createComponent("./TabletBrowser.qml");
if (component.status != Component.Ready) {
if (component.status == Component.Error) {
console.log("Error: " + component.errorString());
}
return;
}
var newWindow = component.createObject();
newWindow.setProfile(webview.profile);
request.openIn(newWindow.webView);
newWindow.eventBridge = web.eventBridge;
stackRoot.push(newWindow);
newWindow.webView.forceActiveFocus();
}
onNavigationRequested: {
if (request.navigationType == WebEngineNavigationRequest.LinkClickedNavigation) {
pagesModel.append({webUrl: request.url.toString()})
}
}
} // item
onNewViewRequested: {
request.openIn(webView);
}
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_L:
@ -183,4 +136,4 @@ Item {
}
}
} // dialog
}

View file

@ -19,12 +19,11 @@ Original.CheckBox {
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property bool isRedCheck: false
property int boxSize: 14
readonly property int boxRadius: 3
readonly property int checkSize: Math.max(boxSize - 8, 10)
readonly property int checkRadius: 2
activeFocusOnPress: true
style: CheckBoxStyle {
@ -37,6 +36,7 @@ Original.CheckBox {
border.color: pressed || hovered
? hifi.colors.checkboxCheckedBorder
: (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish)
gradient: Gradient {
GradientStop {
position: 0.2
@ -68,9 +68,9 @@ Original.CheckBox {
height: checkSize
radius: checkRadius
anchors.centerIn: parent
color: hifi.colors.checkboxChecked
color: isRedCheck ? hifi.colors.checkboxCheckedRed : hifi.colors.checkboxChecked
border.width: 2
border.color: hifi.colors.checkboxCheckedBorder
border.color: isRedCheck? hifi.colors.checkboxCheckedBorderRed : hifi.colors.checkboxCheckedBorder
visible: checked && !pressed || !checked && pressed
}

View file

@ -1,6 +1,6 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.1
import QtWebEngine 1.2
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls
import "../styles" as HifiStyles
@ -14,17 +14,20 @@ Item {
height: parent.height
property var parentStackItem: null
property int headerHeight: 38
property alias url: root.url
property string address: url
property alias scriptURL: root.userScriptUrl
property string url
property string address: url //for compatibility
property string scriptURL
property alias eventBridge: eventBridgeWrapper.eventBridge
property bool keyboardEnabled: HMD.active
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isDesktop: false
property WebEngineView view: root
property WebEngineView view: loader.currentView
property int currentPage: -1 // used as a model for repeater
property alias pagesModel: pagesModel
Row {
id: buttons
HifiConstants { id: hifi }
@ -37,29 +40,29 @@ Item {
anchors.leftMargin: 8
HiFiGlyphs {
id: back;
enabled: true;
enabled: currentPage > 0
text: hifi.glyphs.backward
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: stackRoot.goBack() }
MouseArea { anchors.fill: parent; onClicked: goBack() }
}
HiFiGlyphs {
id: forward;
enabled: stackRoot.currentItem.canGoForward;
enabled: currentPage < pagesModel.count - 1
text: hifi.glyphs.forward
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: stackRoot.currentItem.goForward() }
MouseArea { anchors.fill: parent; onClicked: goForward() }
}
HiFiGlyphs {
id: reload;
enabled: true;
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
enabled: view != null;
text: (view !== null && view.loading) ? hifi.glyphs.close : hifi.glyphs.reload
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: stackRoot.currentItem.reloadPage(); }
MouseArea { anchors.fill: parent; onClicked: reloadPage(); }
}
}
@ -86,7 +89,7 @@ Item {
}
//root.hidePermissionsBar();
web.keyboardRaised = false;
stackRoot.currentItem.gotoPage(text);
gotoPage(text);
break;
@ -94,167 +97,78 @@ Item {
}
}
ListModel {
id: pagesModel
onCountChanged: {
currentPage = count - 1
}
}
function goBack() {
if (currentPage > 0) {
currentPage--;
}
}
function goForward() {
if (currentPage < pagesModel.count - 1) {
currentPage++;
}
}
function gotoPage(url) {
pagesModel.append({webUrl: url})
}
function reloadPage() {
view.reloadAndBypassCache()
view.setActiveFocusOnPress(true);
view.setEnabled(true);
}
onCurrentPageChanged: {
if (currentPage >= 0 && currentPage < pagesModel.count && loader.item !== null) {
loader.item.url = pagesModel.get(currentPage).webUrl
}
}
onUrlChanged: {
gotoPage(url)
}
QtObject {
id: eventBridgeWrapper
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
Loader {
id: loader
property WebEngineView currentView: null
StackView {
id: stackRoot
width: parent.width
height: parent.height - web.headerHeight
asynchronous: true
anchors.top: buttons.bottom
//property var goBack: currentItem.goBack();
property WebEngineView view: root
initialItem: root;
function goBack() {
if (depth > 1 ) {
if (currentItem.canGoBack) {
currentItem.goBack();
} else {
stackRoot.pop();
currentItem.webView.forceActiveFocus();
web.address = currentItem.webView.url;
}
} else {
if (currentItem.canGoBack) {
currentItem.goBack();
} else if (parentStackItem) {
web.parentStackItem.pop();
active: false
source: "../TabletBrowser.qml"
onStatusChanged: {
if (loader.status === Loader.Ready) {
currentView = item.webView
item.webView.userScriptUrl = web.scriptURL
if (currentPage >= 0) {
//we got something to load already
item.url = pagesModel.get(currentPage).webUrl
}
}
}
QtObject {
id: eventBridgeWrapper
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
WebEngineView {
id: root
objectName: "webEngineView"
x: 0
y: 0
width: parent.width
height: keyboardEnabled && keyboardRaised ? (parent.height - keyboard.height) : parent.height
profile: HFTabletWebEngineProfile {
id: webviewTabletProfile
storageName: "qmlTabletWebEngine"
}
property WebEngineView webView: root
function reloadPage() {
root.reload();
}
function gotoPage(url) {
root.url = url;
}
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: root.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
webChannel.registeredObjects: [eventBridgeWrapper]
Component.onCompleted: {
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("WebView.qml");
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
root.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
console.log("[DR] -> printing user string " + root.profile.httpUserAgent);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
onNewViewRequested:{
// desktop is not defined for web-entities
if (web.isDesktop) {
var component = Qt.createComponent("../Browser.qml");
var newWindow = component.createObject(desktop);
newWindow.setProfile(root.profile);
request.openIn(newWindow.webView);
} else {
var component = Qt.createComponent("../TabletBrowser.qml");
if (component.status != Component.Ready) {
if (component.status == Component.Error) {
console.log("Error: " + component.errorString());
}
return;
}
var newWindow = component.createObject();
newWindow.setProfile(root.profile);
request.openIn(newWindow.webView);
newWindow.eventBridge = web.eventBridge;
stackRoot.push(newWindow);
}
}
}
HiFiControls.Keyboard {
id: keyboard
raised: web.keyboardEnabled && web.keyboardRaised
numeric: web.punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
}
}
Component.onCompleted: {
web.isDesktop = (typeof desktop !== "undefined");
address = url;
loader.active = true
}
Keys.onPressed: {

View file

@ -0,0 +1,22 @@
//
// WebEntityView.qml
//
// Created by Kunal Gosar on 16 March 2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
import FileTypeProfile 1.0
WebView {
viewProfile: FileTypeProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
urlTag: "noDownload=true";
}

View file

@ -10,6 +10,7 @@ Item {
property alias eventBridge: eventBridgeWrapper.eventBridge
property alias canGoBack: root.canGoBack;
property var goBack: root.goBack;
property alias urlTag: root.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
property bool punctuationMode: false
@ -27,6 +28,8 @@ Item {
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
property alias viewProfile: root.profile
WebEngineView {
id: root
@ -66,6 +69,8 @@ Item {
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
@ -94,6 +99,7 @@ Item {
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();

View file

@ -127,7 +127,7 @@ Rectangle {
text: hifi.glyphs.mic
color: hifi.colors.primaryHighlight
anchors.verticalCenter: parent.verticalCenter
font.pointSize: 27
size: 32
}
RalewayRegular {
anchors.verticalCenter: parent.verticalCenter
@ -182,7 +182,7 @@ Rectangle {
text: hifi.glyphs.unmuted
color: hifi.colors.primaryHighlight
anchors.verticalCenter: parent.verticalCenter
font.pointSize: 27
size: 32
}
RalewayRegular {
anchors.verticalCenter: parent.verticalCenter

View file

@ -243,12 +243,7 @@ Rectangle {
}
}
}
DropShadow {
anchors.fill: actionIcon
radius: 8.0
color: "#80000000"
source: actionIcon
}
MouseArea {
id: messageArea;
width: rectIcon.width;

View file

@ -12,13 +12,15 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../styles-uit"
import "../controls-uit"
Item {
property var dialogTitleText;
property var optionTitleText;
property var optionBodyText;
property var optionValues;
property var selectedOptionIndex;
property var dialogTitleText : "";
property var optionTitleText: "";
property var optionBodyText: "";
property var optionValues: [];
property var selectedOptionIndex: 0;
property var callbackFunction;
property int dialogWidth;
property int dialogHeight;
property int comboOptionTextSize: 18;
@ -31,6 +33,14 @@ Item {
populateComboListViewModel();
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
combo.visible = false;
}
}
Rectangle {
id: dialogBackground;
anchors.fill: parent;
@ -42,12 +52,12 @@ Item {
id: dialogContainer;
color: "white";
anchors.centerIn: dialogBackground;
width: dialogWidth;
height: dialogHeight;
width: combo.dialogWidth;
height: combo.dialogHeight;
RalewayRegular {
id: dialogTitle;
text: dialogTitleText;
text: combo.dialogTitleText;
anchors.top: parent.top;
anchors.topMargin: 20;
anchors.left: parent.left;
@ -58,6 +68,29 @@ Item {
verticalAlignment: Text.AlignTop;
}
HiFiGlyphs {
id: closeGlyphButton;
text: hifi.glyphs.close;
size: 32;
anchors.verticalCenter: dialogTitle.verticalCenter;
anchors.right: parent.right;
anchors.rightMargin: 20;
MouseArea {
anchors.fill: closeGlyphButton;
hoverEnabled: true;
onEntered: {
parent.text = hifi.glyphs.closeInverted;
}
onExited: {
parent.text = hifi.glyphs.close;
}
onClicked: {
combo.visible = false;
}
}
}
ListModel {
id: comboListViewModel;
}
@ -69,6 +102,7 @@ Item {
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
clip: true;
model: comboListViewModel;
delegate: comboListViewDelegate;
@ -77,13 +111,12 @@ Item {
Rectangle {
id: comboListViewItemContainer;
// Size
height: childrenRect.height + 10;
height: optionTitle.height + optionBody.height + 20;
width: dialogContainer.width;
color: selectedOptionIndex === index ? '#cee6ff' : 'white';
Rectangle {
id: comboOptionSelected;
visible: selectedOptionIndex === index ? true : false;
color: hifi.colors.blueAccent;
color: selectedOptionIndex == index ? hifi.colors.blueAccent : 'white';
anchors.left: parent.left;
anchors.leftMargin: 20;
anchors.top: parent.top;
@ -92,7 +125,7 @@ Item {
height: width;
radius: width;
border.width: 3;
border.color: hifi.colors.blueHighlight;
border.color: selectedOptionIndex === index ? hifi.colors.blueHighlight: hifi.colors.lightGrayText;
}
@ -100,9 +133,11 @@ Item {
id: optionTitle;
text: titleText;
anchors.top: parent.top;
anchors.topMargin: 7;
anchors.left: comboOptionSelected.right;
anchors.leftMargin: 20;
anchors.leftMargin: 10;
anchors.right: parent.right;
anchors.rightMargin: 10;
height: 30;
size: comboOptionTextSize;
wrapMode: Text.WordWrap;
@ -112,10 +147,10 @@ Item {
id: optionBody;
text: bodyText;
anchors.top: optionTitle.bottom;
anchors.bottom: parent.bottom;
anchors.left: comboOptionSelected.right;
anchors.leftMargin: 25;
anchors.right: parent.right;
anchors.rightMargin: 10;
size: comboOptionTextSize;
wrapMode: Text.WordWrap;
}
@ -127,9 +162,8 @@ Item {
onEntered: comboListViewItemContainer.color = hifi.colors.blueHighlight
onExited: comboListViewItemContainer.color = selectedOptionIndex === index ? '#cee6ff' : 'white';
onClicked: {
GlobalServices.findableBy = optionValue;
UserActivityLogger.palAction("set_availability", optionValue);
print('Setting availability:', optionValue);
callbackFunction(optionValue);
combo.visible = false;
}
}
}
@ -137,18 +171,10 @@ Item {
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
combo.visible = false;
}
}
function populateComboListViewModel() {
comboListViewModel.clear();
optionTitleText.forEach(function(titleText, index) {
comboListViewModel.insert(index, {"titleText": titleText, "bodyText": optionBodyText[index], "optionValue": optionValues[index]});
});
}
}
}

View file

@ -85,6 +85,28 @@ Item {
wrapMode: Text.WordWrap
textFormat: Text.StyledText
}
HiFiGlyphs {
id: closeGlyphButton
text: hifi.glyphs.close
size: headerTextPixelSize
anchors.top: parent.top
anchors.topMargin: -20
anchors.right: parent.right
anchors.rightMargin: -25
MouseArea {
anchors.fill: closeGlyphButton
hoverEnabled: true
onEntered: {
parent.text = hifi.glyphs.closeInverted;
}
onExited: {
parent.text = hifi.glyphs.close;
}
onClicked: {
letterbox.visible = false;
}
}
}
}
// Popup Text
Text {

View file

@ -14,6 +14,7 @@ import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
import "../styles-uit"
import "../controls-uit" as HifiControls
import "toolbars"
// references Users, UserActivityLogger, MyAvatar, Vec3, Quat, AddressManager from root context
@ -42,8 +43,9 @@ Item {
property bool selected: false
property bool isAdmin: false
property bool isPresent: true
property string placeName: ""
property string profilePicBorderColor: (connectionStatus == "connection" ? hifi.colors.indigoAccent : (connectionStatus == "friend" ? hifi.colors.greenHighlight : "transparent"))
property alias avImage: avatarImage
Item {
id: avatarImage
visible: profileUrl !== "" && userName !== "";
@ -79,25 +81,6 @@ Item {
anchors.fill: parent;
visible: userImage.status != Image.Ready;
}
StateImage {
id: infoHoverImage;
visible: false;
imageURL: "../../images/info-icon-2-state.svg";
size: 32;
buttonState: 1;
anchors.centerIn: parent;
}
MouseArea {
anchors.fill: parent
enabled: selected || isMyCard;
hoverEnabled: enabled
onClicked: {
userInfoViewer.url = defaultBaseUrl + "/users/" + userName;
userInfoViewer.visible = true;
}
onEntered: infoHoverImage.visible = true;
onExited: infoHoverImage.visible = false;
}
}
// Colored border around avatarImage
@ -316,9 +299,10 @@ Item {
visible: thisNameCard.userName !== "";
// Size
width: parent.width
height: pal.activeTab == "nearbyTab" || isMyCard ? usernameTextPixelSize + 4 : parent.height;
height: usernameTextPixelSize + 4
// Anchors
anchors.top: isMyCard ? myDisplayName.bottom : (pal.activeTab == "nearbyTab" ? displayNameContainer.bottom : parent.top);
anchors.top: isMyCard ? myDisplayName.bottom : pal.activeTab == "nearbyTab" ? displayNameContainer.bottom : undefined //(parent.height - displayNameTextPixelSize/2));
anchors.verticalCenter: pal.activeTab == "connectionsTab" ? avatarImage.verticalCenter : undefined
anchors.left: avatarImage.right;
anchors.leftMargin: avatarImage.visible ? 5 : 0;
anchors.rightMargin: 5;
@ -346,6 +330,92 @@ Item {
}
}
}
StateImage {
id: nameCardConnectionInfoImage
visible: selected && !isMyCard && pal.activeTab == "connectionsTab"
imageURL: "../../images/info-icon-2-state.svg" // PLACEHOLDER!!!
size: 32;
buttonState: 0;
anchors.left: avatarImage.right
anchors.bottom: parent.bottom
}
MouseArea {
anchors.fill:nameCardConnectionInfoImage
enabled: selected
hoverEnabled: true
onClicked: {
userInfoViewer.url = defaultBaseUrl + "/users/" + userName;
userInfoViewer.visible = true;
}
onEntered: {
nameCardConnectionInfoImage.buttonState = 1;
}
onExited: {
nameCardConnectionInfoImage.buttonState = 0;
}
}
FiraSansRegular {
id: nameCardConnectionInfoText
visible: selected && !isMyCard && pal.activeTab == "connectionsTab" && !isMyCard
width: parent.width
height: displayNameTextPixelSize
size: displayNameTextPixelSize - 4
anchors.left: nameCardConnectionInfoImage.right
anchors.verticalCenter: nameCardConnectionInfoImage.verticalCenter
anchors.leftMargin: 5
verticalAlignment: Text.AlignVCenter
text: "Info"
color: hifi.colors.baseGray
}
HiFiGlyphs {
id: nameCardRemoveConnectionImage
visible: selected && !isMyCard && pal.activeTab == "connectionsTab"
text: hifi.glyphs.close
size: 28;
x: 120
anchors.verticalCenter: nameCardConnectionInfoImage.verticalCenter
}
MouseArea {
anchors.fill:nameCardRemoveConnectionImage
enabled: selected
hoverEnabled: true
onClicked: {
// send message to pal.js to forgetConnection
pal.sendToScript({method: 'removeConnection', params: thisNameCard.userName});
}
onEntered: {
nameCardRemoveConnectionImage.text = hifi.glyphs.closeInverted;
}
onExited: {
nameCardRemoveConnectionImage.text = hifi.glyphs.close;
}
}
FiraSansRegular {
id: nameCardRemoveConnectionText
visible: selected && !isMyCard && pal.activeTab == "connectionsTab" && !isMyCard
width: parent.width
height: displayNameTextPixelSize
size: displayNameTextPixelSize - 4
anchors.left: nameCardRemoveConnectionImage.right
anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter
anchors.leftMargin: 5
verticalAlignment: Text.AlignVCenter
text: "Forget"
color: hifi.colors.baseGray
}
HifiControls.Button {
id: visitConnectionButton
visible: selected && !isMyCard && pal.activeTab == "connectionsTab" && !isMyCard
text: "Visit"
enabled: thisNameCard.placeName !== ""
anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter
x: 240
onClicked: {
AddressManager.goToUser(thisNameCard.userName);
UserActivityLogger.palAction("go_to_user", thisNameCard.userName);
}
}
// VU Meter
Rectangle {
id: nameCardVUMeter
@ -484,7 +554,7 @@ Item {
}
}
}
function updateGainFromQML(avatarUuid, sliderValue, isReleased) {
Users.setAvatarGain(avatarUuid, sliderValue);
if (isReleased) {

View file

@ -52,11 +52,18 @@ Rectangle {
id: letterboxMessage;
z: 999; // Force the popup on top of everything else
}
Connections {
target: GlobalServices
onMyUsernameChanged: {
myData.userName = Account.username;
myDataChanged(); // Setting a property within an object isn't enough to update dependencies. This will do it.
}
}
// The ComboDialog used for setting availability
ComboDialog {
id: comboDialog;
z: 999; // Force the ComboDialog on top of everything else
dialogWidth: parent.width - 100;
dialogWidth: parent.width - 50;
dialogHeight: parent.height - 100;
}
function letterbox(headerGlyph, headerText, message) {
@ -66,7 +73,13 @@ Rectangle {
letterboxMessage.visible = true;
letterboxMessage.popupRadius = 0;
}
function popupComboDialogCallback(availability) {
GlobalServices.findableBy = availability;
UserActivityLogger.palAction("set_availability", availability);
print('Setting availability:', JSON.stringify(GlobalServices.findableBy));
}
function popupComboDialog(dialogTitleText, optionTitleText, optionBodyText, optionValues) {
comboDialog.callbackFunction = popupComboDialogCallback;
comboDialog.dialogTitleText = dialogTitleText;
comboDialog.optionTitleText = optionTitleText;
comboDialog.optionBodyText = optionBodyText;
@ -295,12 +308,11 @@ Rectangle {
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
enabled: activeTab === "connectionsTab";
onClicked: letterbox(hifi.glyphs.question,
"Connections and Friends",
"<font color='purple'>Purple borders around profile pictures are <b>Connections</b>.</font><br>" +
"<font color='purple'>Purple borders around profile pictures represent <b>Connections</b>.</font><br>" +
"When your availability is set to Everyone, Connections can see your username and location.<br><br>" +
"<font color='green'>Green borders around profile pictures are <b>Friends</b>.</font><br>" +
"<font color='green'>Green borders around profile pictures represent <b>Friends</b>.</font><br>" +
"When your availability is set to Friends, only Friends can see your username and location.");
onEntered: connectionsHelpText.color = hifi.colors.blueHighlight;
onExited: connectionsHelpText.color = hifi.colors.blueAccent;
@ -430,7 +442,7 @@ Rectangle {
rowDelegate: Rectangle { // The only way I know to specify a row height.
// Size
height: rowHeight + (styleData.selected ? 15 : 0);
color: rowColor(styleData.selected, styleData.alternate);
color: nearbyRowColor(styleData.selected, styleData.alternate);
}
// This Item refers to the contents of each Cell
@ -506,6 +518,7 @@ Rectangle {
// If this is an "Ignore" checkbox, disable the checkbox if user isn't present.
enabled: styleData.role === "ignore" ? (model ? model["isPresent"] : true) : true;
boxSize: 24;
isRedCheck: true
onClicked: {
var newValue = !model[styleData.role];
nearbyUserModel.setProperty(model.userIndex, styleData.role, newValue);
@ -605,7 +618,7 @@ Rectangle {
"Bold names in the list are <b>avatar display names</b>.<br>" +
"<font color='purple'>Purple borders around profile pictures are <b>connections</b></font>.<br>" +
"<font color='green'>Green borders around profile pictures are <b>friends</b>.</font><br>" +
"(TEMPORARY LANGUAGE) In some situations, you can also see others' usernames.<br>" +
"Others can find you and see your username according to your <b>availability</b> settings.<br>" +
"If you can see someone's username, you can GoTo them by selecting them in the PAL, then clicking their name.<br>" +
"<br>If someone's display name isn't set, a unique <b>session display name</b> is assigned to them.<br>" +
"<br>Administrators of this domain can also see the <b>username</b> or <b>machine ID</b> associated with each avatar present.");
@ -742,7 +755,7 @@ Rectangle {
resizable: false;
}
TableViewColumn {
role: "friends";
role: "connection";
title: "FRIEND";
width: actionButtonWidth;
movable: false;
@ -756,8 +769,8 @@ Rectangle {
// This Rectangle refers to each Row in the connectionsTable.
rowDelegate: Rectangle {
// Size
height: rowHeight;
color: rowColor(styleData.selected, styleData.alternate);
height: rowHeight + (styleData.selected ? 15 : 0);
color: connectionsRowColor(styleData.selected, styleData.alternate);
}
// This Item refers to the contents of each Cell
@ -772,6 +785,7 @@ Rectangle {
profileUrl: (model && model.profileUrl) || "";
displayName: "";
userName: model ? model.userName : "";
placeName: model ? model.placeName : ""
connectionStatus : model ? model.connection : "";
selected: styleData.selected;
// Size
@ -790,12 +804,16 @@ Rectangle {
elide: Text.ElideRight;
// Size
width: parent.width;
// Anchors
anchors.fill: parent;
// you would think that this would work:
// anchors.verticalCenter: connectionsNameCard.avImage.verticalCenter
// but no! you cannot anchor to a non-sibling or parent. So I will
// align with the friends checkbox, where I did the manual alignment
anchors.verticalCenter: friendsCheckBox.verticalCenter
// Text Size
size: 16;
// Text Positioning
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
// Style
color: hifi.colors.blueAccent;
font.underline: true;
@ -815,22 +833,21 @@ Rectangle {
// "Friends" checkbox
HifiControlsUit.CheckBox {
id: friendsCheckBox;
visible: styleData.role === "friends" && model.userName !== myData.userName;
anchors.centerIn: parent;
checked: model ? (model["connection"] === "friend" ? true : false) : false;
visible: styleData.role === "connection" && model && model.userName !== myData.userName;
// you would think that this would work:
// anchors.verticalCenter: connectionsNameCard.avImage.verticalCenter
// but no! you cannot anchor to a non-sibling or parent. So:
x: parent.width/2 - boxSize/2;
y: connectionsNameCard.avImage.y + connectionsNameCard.avImage.height/2 - boxSize/2;
checked: model && (model.connection === "friend");
boxSize: 24;
onClicked: {
var newValue = !(model["connection"] === "friend");
var newValue = model.connection !== "friend";
connectionsUserModel.setProperty(model.userIndex, styleData.role, newValue);
connectionsUserModelData[model.userIndex][styleData.role] = newValue; // Defensive programming
pal.sendToScript({method: newValue ? 'addFriend' : 'removeFriend', params: model.userName});
UserActivityLogger["palAction"](newValue ? styleData.role : "un-" + styleData.role, model.sessionId);
// http://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html#creating-property-bindings-from-javascript
// I'm using an explicit binding here because clicking a checkbox breaks the implicit binding as set by
// "checked:" statement above.
checked = Qt.binding(function() { return (model["connection"] === "friend" ? true : false)});
}
}
}
@ -894,7 +911,7 @@ Rectangle {
wrapMode: Text.WordWrap
textFormat: Text.StyledText;
// Text
text: HMD.active ?
text: HMD.isMounted ?
"<b>When you meet someone you want to remember later, you can <font color='purple'>connect</font> with a handshake:</b><br><br>" +
"1. Put your hand out onto their hand and squeeze your controller's grip button on its side.<br>" +
"2. Once the other person puts their hand onto yours, you'll see your connection form.<br>" +
@ -942,7 +959,7 @@ Rectangle {
}
Item {
id: upperRightInfoContainer;
width: 160;
width: 200;
height: parent.height;
anchors.top: parent.top;
anchors.right: parent.right;
@ -953,59 +970,52 @@ Rectangle {
// Text size
size: hifi.fontSizes.tabularData;
// Anchors
anchors.top: availabilityComboBox.bottom;
anchors.horizontalCenter: parent.horizontalCenter;
anchors.left: parent.left;
// Style
color: hifi.colors.baseGrayHighlight;
// Alignment
horizontalAlignment: Text.AlignHCenter;
horizontalAlignment: Text.AlignLeft;
verticalAlignment: Text.AlignTop;
}
/*Rectangle {
Rectangle {
property var availabilityStrings: ["Everyone", "Friends and Connections", "Friends Only", "Appear Offline"];
id: availabilityComboBox;
color: hifi.colors.textFieldLightBackground
// Anchors
anchors.top: parent.top;
anchors.top: availabilityText.bottom;
anchors.horizontalCenter: parent.horizontalCenter;
// Size
width: parent.width;
height: 40;
function determineAvailabilityIndex() {
return ['all', 'connections', 'friends', 'none'].indexOf(GlobalServices.findableBy);
}
function determineAvailabilityString() {
return availabilityStrings[determineAvailabilityIndex()];
}
RalewayRegular {
text: myData.userName === "Unknown user" ? "Login to Set" : availabilityComboBox.determineAvailabilityString();
anchors.fill: parent;
anchors.leftMargin: 10;
horizontalAlignment: Text.AlignLeft;
size: 16;
}
MouseArea {
anchors.fill: parent
anchors.fill: parent;
enabled: myData.userName !== "Unknown user";
hoverEnabled: true;
onClicked: {
popupComboDialog("Set your list visibility",
["Everyone", "Friends and Connections", "Friends Only", "Appear Offline"],
["You will be invisible in everyone's 'People' list.\nAnyone will be able to jump to your location if the domain allows.",
"You will be visible in the 'People' list only for those with whom you are connected or friends.\nThey will be able to jump to your location if the domain allows.",
"You will be visible in the 'People' list only for those with whom you are friends.\nThey will be able to jump to your location if the domain allows.",
"You will not be visible in the 'People' list of any other users."],
popupComboDialog("Set your availability:",
availabilityComboBox.availabilityStrings,
["Your username will be visible in everyone's 'Nearby' list.\nAnyone will be able to jump to your location from within the 'Nearby' list.",
"Your location will be visible in the 'Connections' list only for those with whom you are connected or friends.\nThey will be able to jump to your location if the domain allows.",
"Your location will be visible in the 'Connections' list only for those with whom you are friends.\nThey will be able to jump to your location if the domain allows.",
"Your location will not be visible in the 'Connections' list of any other users. Only domain admins will be able to see your username in the 'Nearby' list."],
["all", "connections", "friends", "none"]);
}
}
}*/
HifiControlsUit.ComboBox {
function determineAvailabilityIndex() {
return ['all', 'connections', 'friends', 'none'].indexOf(GlobalServices.findableBy)
}
id: availabilityComboBox;
// Anchors
anchors.top: parent.top;
anchors.horizontalCenter: parent.horizontalCenter;
// Size
width: parent.width;
height: 40;
currentIndex: determineAvailabilityIndex();
model: ListModel {
id: availabilityComboBoxListItems
ListElement { text: "Everyone"; value: "all"; }
ListElement { text: "All Connections"; value: "connections"; }
ListElement { text: "Friends Only"; value: "friends"; }
ListElement { text: "Appear Offline"; value: "none" }
}
onCurrentIndexChanged: {
GlobalServices.findableBy = availabilityComboBoxListItems.get(currentIndex).value;
UserActivityLogger.palAction("set_availability", availabilityComboBoxListItems.get(currentIndex).value);
print('Setting availability:', JSON.stringify(GlobalServices.findableBy));
onEntered: availabilityComboBox.color = hifi.colors.lightGrayText;
onExited: availabilityComboBox.color = hifi.colors.textFieldLightBackground;
}
}
}
@ -1183,9 +1193,12 @@ Rectangle {
}
}
function rowColor(selected, alternate) {
function nearbyRowColor(selected, alternate) {
return selected ? hifi.colors.orangeHighlight : alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd;
}
function connectionsRowColor(selected, alternate) {
return selected ? hifi.colors.lightBlueHighlight : alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd;
}
function findNearbySessionIndex(sessionId, optionalData) { // no findIndex in .qml
var data = optionalData || nearbyUserModelData, length = data.length;
for (var i = 0; i < length; i++) {
@ -1256,6 +1269,8 @@ Rectangle {
selectionTimer.userIndex = userIndex;
selectionTimer.start();
}
// in any case make sure we are in the nearby tab
activeTab="nearbyTab";
break;
// Received an "updateUsername()" request from the JS
case 'updateUsername':

View file

@ -21,6 +21,9 @@ Rectangle {
id: root
objectName: "AssetServer"
property string title: "Asset Browser"
property bool keyboardRaised: false
property var eventBridge;
signal sendToScript(var message);
property bool isHMD: false
@ -415,7 +418,6 @@ Rectangle {
Column {
width: parent.width
y: hifi.dimensions.tabletMenuHeader //-bgNavBar
spacing: 10
HifiControls.TabletContentSection {

View file

@ -20,7 +20,7 @@ import "../../windows"
Rectangle {
id: root
objectName: "RunningScripts"
property var title: "Running Scripts"
property string title: "Running Scripts"
HifiConstants { id: hifi }
signal sendToScript(var message);
property var eventBridge;
@ -81,9 +81,9 @@ Rectangle {
Flickable {
id: flickable
width: parent.width
width: tabletRoot.width
height: parent.height - (keyboard.raised ? keyboard.raisedHeight : 0)
contentWidth: parent.width
contentWidth: column.width
contentHeight: column.childrenRect.height
clip: true
@ -121,9 +121,8 @@ Rectangle {
model: runningScriptsModel
id: table
height: 185
width: parent.width
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.right: parent.right
expandSelectedRow: true
itemDelegate: Item {

View file

@ -22,15 +22,20 @@ Rectangle {
color: hifi.colors.baseGray;
property var eventBridge;
signal sendToScript(var message);
property bool keyboardEnabled: false
property bool punctuationMode: false
property bool keyboardRasied: false
Column {
Item {
id: column1
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 10
anchors.fill: parent
spacing: 5
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: keyboard.top
Text {
id: text1
@ -43,17 +48,42 @@ Rectangle {
id: modelURL
height: 20
text: qsTr("")
color: "white"
anchors.top: text1.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
font.pixelSize: 12
onAccepted: {
newModelDialog.keyboardEnabled = false;
}
MouseArea {
anchors.fill: parent
onClicked: {
newModelDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus()
}
}
}
Rectangle {
id: textInputBox
color: "white"
anchors.fill: modelURL
opacity: 0.1
}
Row {
id: row1
height: 400
spacing: 30
anchors.top: modelURL.top
anchors.topMargin: 25
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
@ -155,4 +185,15 @@ Rectangle {
}
}
}
Keyboard {
id: keyboard
raised: parent.keyboardEnabled
numeric: parent.punctuationMode
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
}
}

View file

@ -202,7 +202,7 @@ Item {
RalewaySemiBold {
id: usernameText
text: tablet.parent.parent.username
text: tabletRoot.username
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 20

View file

@ -25,22 +25,33 @@ StackView {
HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifiStyleConstants }
initialItem: addressBarDialog
width: parent.width
height: parent.height
width: parent !== null ? parent.width : undefined
height: parent !== null ? parent.height : undefined
property var eventBridge;
property var allStories: [];
property int cardWidth: 460;
property int cardHeight: 320;
property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/";
property var tablet: null;
property bool isDesktop: false;
Component { id: tabletStoryCard; TabletStoryCard {} }
Component.onCompleted: {
root.currentItem.focus = true;
root.currentItem.forceActiveFocus();
addressLine.focus = true;
addressLine.forceActiveFocus();
fillDestinations();
updateLocationText();
updateLocationText(false);
root.parentChanged.connect(center);
center();
isDesktop = (typeof desktop !== "undefined");
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
if (desktop) {
root.title = "GOTO";
}
}
Component.onDestruction: {
root.parentChanged.disconnect(center);
@ -63,8 +74,8 @@ StackView {
root.push(card);
return;
}
addressLine.text = targetString;
toggleOrGo(true);
location.text = targetString;
toggleOrGo(true, targetString);
clearAddressLineTimer.start();
}
@ -107,7 +118,9 @@ StackView {
imageURL: "../../../images/home.svg"
onClicked: {
addressBarDialog.loadHome();
root.shown = false;
tabletRoot.shown = false;
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.gotoHomeScreen();
}
anchors {
left: parent.left
@ -142,7 +155,9 @@ StackView {
anchors {
top: navBar.bottom
right: parent.right
rightMargin: 16
left: parent.left
leftMargin: 16
}
property int inputAreaHeight: 70
@ -291,9 +306,8 @@ StackView {
left: parent.left
right: parent.right
leftMargin: 10
verticalCenter: parent.verticalCenter;
horizontalCenter: parent.horizontalCenter;
}
model: suggestions
orientation: ListView.Vertical
@ -539,18 +553,29 @@ StackView {
}
}
function toggleOrGo(fromSuggestions) {
function toggleOrGo(fromSuggestions, address) {
if (address !== undefined && address !== "") {
addressBarDialog.loadAddress(address, fromSuggestions)
}
if (addressLine.text !== "") {
addressBarDialog.loadAddress(addressLine.text, fromSuggestions)
}
root.shown = false;
if (isDesktop) {
tablet.gotoHomeScreen();
} else {
HMD.closeTablet();
}
tabletRoot.shown = false;
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
root.shown = false
tabletRoot.shown = false
clearAddressLineTimer.start();
event.accepted = true
break

View file

@ -13,6 +13,7 @@ Item {
property var openMessage: null;
property string subMenu: ""
signal showDesktop();
property bool shown: true
function setOption(value) {
option = value;

View file

@ -89,14 +89,17 @@ Preference {
if (categoryPreferences) {
console.log("Category " + root.name + " with " + categoryPreferences.length + " preferences");
for (var j = 0; j < categoryPreferences.length; ++j) {
buildPreference(categoryPreferences[j]);
//provide component position within column
//lowest numbers on top
buildPreference(categoryPreferences[j], j);
}
}
}
function buildPreference(preference) {
function buildPreference(preference, itemNum) {
console.log("\tPreference type " + preference.type + " name " + preference.name)
var builder;
var zpos;
switch (preference.type) {
case Preference.Editable:
checkBoxCount = 0;
@ -136,11 +139,14 @@ Preference {
case Preference.ComboBox:
checkBoxCount = 0;
builder = comboBoxBuilder;
//make sure that combo boxes sitting higher will have higher z coordinate
//to be not overlapped when drop down is active
zpos = root.z + 1000 - itemNum
break;
};
if (builder) {
preferences.push(builder.createObject(contentContainer, { preference: preference, isFirstCheckBox: (checkBoxCount === 1) }));
preferences.push(builder.createObject(contentContainer, { preference: preference, isFirstCheckBox: (checkBoxCount === 1) , z: zpos}));
}
}
}

View file

@ -12,7 +12,10 @@ Item {
property bool pinned: false
clip: true
function updateYOffset() { yOffset = size * buttonState; }
function updateYOffset() {
//make sure offset not set outside image
yOffset = (size * buttonState >= image.height) ? image.height - size : size * buttonState
}
onButtonStateChanged: updateYOffset();
Component.onCompleted: {

View file

@ -70,6 +70,10 @@ Item {
readonly property color indigoAccent: "#9495FF"
readonly property color magentaHighlight: "#EF93D1"
readonly property color magentaAccent: "#A2277C"
readonly property color checkboxCheckedRed: "#FF0000"
readonly property color checkboxCheckedBorderRed: "#D00000"
readonly property color lightBlueHighlight: "#d6f6ff"
// Semitransparent
readonly property color darkGray30: "#4d121212"
readonly property color darkGray0: "#00121212"

View file

@ -142,6 +142,7 @@
#include "ModelPackager.h"
#include "networking/HFWebEngineProfile.h"
#include "networking/HFTabletWebEngineProfile.h"
#include "networking/FileTypeProfile.h"
#include "scripting/TestScriptingInterface.h"
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h"
@ -218,6 +219,7 @@ static const QString FST_EXTENSION = ".fst";
static const QString FBX_EXTENSION = ".fbx";
static const QString OBJ_EXTENSION = ".obj";
static const QString AVA_JSON_EXTENSION = ".ava.json";
static const QString WEB_VIEW_TAG = "noDownload=true";
static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
@ -1934,6 +1936,7 @@ void Application::initializeUi() {
qmlRegisterType<HFWebEngineProfile>("HFWebEngineProfile", 1, 0, "HFWebEngineProfile");
qmlRegisterType<HFTabletWebEngineProfile>("HFTabletWebEngineProfile", 1, 0, "HFTabletWebEngineProfile");
qmlRegisterType<FileTypeProfile>("FileTypeProfile", 1, 0, "FileTypeProfile");
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->qglContext());
@ -2010,6 +2013,7 @@ void Application::initializeUi() {
rootContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
rootContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
rootContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
@ -4383,6 +4387,10 @@ void Application::update(float deltaTime) {
auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix;
myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix));
controller::Pose leftFootPose = userInputMapper->getPoseState(controller::Action::LEFT_FOOT);
controller::Pose rightFootPose = userInputMapper->getPoseState(controller::Action::RIGHT_FOOT);
myAvatar->setFootControllerPosesInSensorFrame(leftFootPose.transform(avatarToSensorMatrix), rightFootPose.transform(avatarToSensorMatrix));
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
updateDialogs(deltaTime); // update various stats dialogs if present
@ -5032,7 +5040,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
// TODO fix shadows and make them use the GPU library
// The pending changes collecting the changes here
render::PendingChanges pendingChanges;
render::Transaction transaction;
// FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities
// Background rendering decision
@ -5040,7 +5048,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
auto backgroundRenderData = make_shared<BackgroundRenderData>();
auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData);
BackgroundRenderData::_item = _main3DScene->allocateID();
pendingChanges.resetItem(BackgroundRenderData::_item, backgroundRenderPayload);
transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload);
}
// Assuming nothing get's rendered through that
@ -5058,7 +5066,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
static_cast<int>(RenderArgs::RENDER_DEBUG_HULLS));
}
renderArgs->_debugFlags = renderDebugFlags;
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges);
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction);
}
}
@ -5070,9 +5078,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
WorldBoxRenderData::_item = _main3DScene->allocateID();
pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
} else {
pendingChanges.updateItem<WorldBoxRenderData>(WorldBoxRenderData::_item,
transaction.updateItem<WorldBoxRenderData>(WorldBoxRenderData::_item,
[](WorldBoxRenderData& payload) {
payload._val++;
});
@ -5085,10 +5093,10 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
}
{
PerformanceTimer perfTimer("SceneProcessPendingChanges");
_main3DScene->enqueuePendingChanges(pendingChanges);
PerformanceTimer perfTimer("SceneProcessTransaction");
_main3DScene->enqueueTransaction(transaction);
_main3DScene->processPendingChangesQueue();
_main3DScene->processTransactionQueue();
}
// For now every frame pass the renderContext
@ -5541,7 +5549,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
bool Application::canAcceptURL(const QString& urlString) const {
QUrl url(urlString);
if (urlString.startsWith(HIFI_URL_SCHEME)) {
if (url.query().contains(WEB_VIEW_TAG)) {
return false;
} else if (urlString.startsWith(HIFI_URL_SCHEME)) {
return true;
}
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
@ -5649,7 +5659,9 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
QUrl scriptURL { scriptFilenameOrURL };
if (scriptURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
shortName = shortName.mid(shortName.lastIndexOf('/') + 1);
int startIndex = shortName.lastIndexOf('/') + 1;
int endIndex = shortName.lastIndexOf('?');
shortName = shortName.mid(startIndex, endIndex - startIndex);
}
QString message = "Would you like to run this script:\n" + shortName;
@ -5782,22 +5794,10 @@ void Application::toggleRunningScriptsWidget() const {
}
void Application::showScriptLogs() {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
auto scriptEngines = DependencyManager::get<ScriptEngines>();
QUrl defaultScriptsLoc = defaultScriptsLocation();
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js");
if (tablet->getToolbarMode()) {
scriptEngines->loadScript(defaultScriptsLoc.toString());
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
if (!tabletRoot && !isHMDMode()) {
scriptEngines->loadScript(defaultScriptsLoc.toString());
} else {
tablet->pushOntoStack("../../hifi/dialogs/TabletDebugWindow.qml");
}
}
scriptEngines->loadScript(defaultScriptsLoc.toString());
}
void Application::showAssetServerWidget(QString filePath) {

View file

@ -54,7 +54,7 @@ void DiscoverabilityManager::updateLocation() {
const QString CONNECTED_KEY_IN_LOCATION = "connected";
locationObject.insert(CONNECTED_KEY_IN_LOCATION, discoverable && domainHandler.isConnected());
if (discoverable) { // Don't consider changes to these as update-worthy if we're not discoverable.
if (discoverable || _lastLocationObject.isEmpty()) { // Don't consider changes to these as update-worthy if we're not discoverable.
const QString PATH_KEY_IN_LOCATION = "path";
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);

View file

@ -476,34 +476,34 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
return displayNameRenderer;
}
bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
auto avatarPayload = new render::Payload<AvatarData>(self);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
_renderItemID = scene->allocateID();
pendingChanges.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel->addToScene(scene, pendingChanges);
transaction.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel->addToScene(scene, transaction);
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->addToScene(scene, pendingChanges);
attachmentModel->addToScene(scene, transaction);
}
_inScene = true;
return true;
}
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemID);
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
transaction.removeItem(_renderItemID);
render::Item::clearID(_renderItemID);
_skeletonModel->removeFromScene(scene, pendingChanges);
_skeletonModel->removeFromScene(scene, transaction);
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->removeFromScene(scene, pendingChanges);
attachmentModel->removeFromScene(scene, transaction);
}
_inScene = false;
}
void Avatar::updateRenderItem(render::PendingChanges& pendingChanges) {
void Avatar::updateRenderItem(render::Transaction& transaction) {
if (render::Item::isValidID(_renderItemID)) {
pendingChanges.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
transaction.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
}
}
@ -680,24 +680,24 @@ void Avatar::fixupModelsInScene() {
// check to see if when we added our models to the scene they were ready, if they were not ready, then
// fix them up in the scene
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
render::Transaction transaction;
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
_skeletonModel->removeFromScene(scene, pendingChanges);
_skeletonModel->addToScene(scene, pendingChanges);
_skeletonModel->removeFromScene(scene, transaction);
_skeletonModel->addToScene(scene, transaction);
}
for (auto attachmentModel : _attachmentModels) {
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
attachmentModel->removeFromScene(scene, pendingChanges);
attachmentModel->addToScene(scene, pendingChanges);
attachmentModel->removeFromScene(scene, transaction);
attachmentModel->addToScene(scene, transaction);
}
}
for (auto attachmentModelToRemove : _attachmentsToRemove) {
attachmentModelToRemove->removeFromScene(scene, pendingChanges);
attachmentModelToRemove->removeFromScene(scene, transaction);
}
_attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end());
_attachmentsToRemove.clear();
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
@ -1422,14 +1422,14 @@ QList<QVariant> Avatar::getSkeleton() {
void Avatar::addToScene(AvatarSharedPointer myHandle) {
render::ScenePointer scene = qApp->getMain3DScene();
if (scene) {
render::PendingChanges pendingChanges;
render::Transaction transaction;
auto nodelist = DependencyManager::get<NodeList>();
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()
&& !nodelist->isIgnoringNode(getSessionUUID())
&& !nodelist->isRadiusIgnoringNode(getSessionUUID())) {
addToScene(myHandle, scene, pendingChanges);
addToScene(myHandle, scene, transaction);
}
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
} else {
qCWarning(interfaceapp) << "AvatarManager::addAvatar() : Unexpected null scene, possibly during application shutdown";
}

View file

@ -82,12 +82,12 @@ public:
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition);
bool addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges);
render::Transaction& transaction);
void removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges);
render::Transaction& transaction);
void updateRenderItem(render::PendingChanges& pendingChanges);
void updateRenderItem(render::Transaction& transaction);
virtual void postUpdate(float deltaTime);

View file

@ -104,11 +104,11 @@ void AvatarManager::init() {
this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection);
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
render::Transaction transaction;
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
_myAvatar->addToScene(_myAvatar, scene, pendingChanges);
_myAvatar->addToScene(_myAvatar, scene, transaction);
}
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
void AvatarManager::updateMyAvatar(float deltaTime) {
@ -192,7 +192,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
return false;
});
render::PendingChanges pendingChanges;
render::Transaction transaction;
uint64_t startTime = usecTimestampNow();
const uint64_t UPDATE_BUDGET = 2000; // usec
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
@ -228,7 +228,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
numAvatarsUpdated++;
}
avatar->simulate(deltaTime, inView);
avatar->updateRenderItem(pendingChanges);
avatar->updateRenderItem(transaction);
avatar->setLastRenderUpdateTime(startTime);
} else {
// we've spent our full time budget --> bail on the rest of the avatar updates
@ -262,7 +262,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
_avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC;
_numAvatarsUpdated = numAvatarsUpdated;
_numAvatarsNotUpdated = numAVatarsNotUpdated;
qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges);
qApp->getMain3DScene()->enqueueTransaction(transaction);
simulateAvatarFades(deltaTime);
}
@ -283,13 +283,13 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
const float MIN_FADE_SCALE = MIN_AVATAR_SCALE;
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
render::Transaction transaction;
while (fadingIterator != _avatarFades.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator);
avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
avatar->animateScaleChanges(deltaTime);
if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
avatar->removeFromScene(*fadingIterator, scene, transaction);
// only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine
if (_motionStatesToRemoveFromPhysics.empty()) {
fadingIterator = _avatarFades.erase(fadingIterator);
@ -302,7 +302,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
++fadingIterator;
}
}
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
AvatarSharedPointer AvatarManager::newSharedAvatar() {
@ -479,17 +479,17 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
for (auto avatarData : _avatarHash) {
auto avatar = std::static_pointer_cast<Avatar>(avatarData);
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
avatar->addToScene(avatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
avatar->addToScene(avatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
} else {
for (auto avatarData : _avatarHash) {
auto avatar = std::static_pointer_cast<Avatar>(avatarData);
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
avatar->removeFromScene(avatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
avatar->removeFromScene(avatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
}
}

View file

@ -205,10 +205,10 @@ void CauterizedModel::updateRenderItems() {
uint32_t deleteGeometryCounter = self->getGeometryCounter();
render::PendingChanges pendingChanges;
render::Transaction transaction;
QList<render::ItemID> keys = self->getRenderItems().keys();
foreach (auto itemID, keys) {
pendingChanges.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) {
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) {
if (data._model && data._model->isLoaded()) {
// Ensure the model geometry was not reset between frames
if (deleteGeometryCounter == data._model->getGeometryCounter()) {
@ -233,7 +233,7 @@ void CauterizedModel::updateRenderItems() {
});
}
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
});
} else {
Model::updateRenderItems();

View file

@ -71,6 +71,8 @@ void Head::reset() {
}
void Head::simulate(float deltaTime, bool isMine) {
const float NORMAL_HZ = 60.0f; // the update rate the constant values were tuned for
// Update audio trailing average for rendering facial animations
const float AUDIO_AVERAGING_SECS = 0.05f;
const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
@ -94,7 +96,7 @@ void Head::simulate(float deltaTime, bool isMine) {
if (typeid(*faceTracker) == typeid(DdeFaceTracker)) {
if (Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) {
calculateMouthShapes();
calculateMouthShapes(deltaTime);
const int JAW_OPEN_BLENDSHAPE = 21;
const int MMMM_BLENDSHAPE = 34;
@ -116,7 +118,7 @@ void Head::simulate(float deltaTime, bool isMine) {
_isEyeTrackerConnected = eyeTracker->isTracking();
}
}
if (!_isFaceTrackerConnected) {
if (!_isEyeTrackerConnected) {
@ -144,22 +146,23 @@ void Head::simulate(float deltaTime, bool isMine) {
_timeWithoutTalking += deltaTime;
if ((_averageLoudness - _longTermAverageLoudness) > TALKING_LOUDNESS) {
_timeWithoutTalking = 0.0f;
} else if (_timeWithoutTalking < BLINK_AFTER_TALKING && _timeWithoutTalking >= BLINK_AFTER_TALKING) {
forceBlink = true;
}
// Update audio attack data for facial animation (eyebrows and mouth)
const float AUDIO_ATTACK_AVERAGING_RATE = 0.9f;
_audioAttack = AUDIO_ATTACK_AVERAGING_RATE * _audioAttack + (1.0f - AUDIO_ATTACK_AVERAGING_RATE) * fabs((_audioLoudness - _longTermAverageLoudness) - _lastLoudness);
float audioAttackAveragingRate = (10.0f - deltaTime * NORMAL_HZ) / 10.0f; // --> 0.9 at 60 Hz
_audioAttack = audioAttackAveragingRate * _audioAttack +
(1.0f - audioAttackAveragingRate) * fabs((_audioLoudness - _longTermAverageLoudness) - _lastLoudness);
_lastLoudness = (_audioLoudness - _longTermAverageLoudness);
const float BROW_LIFT_THRESHOLD = 100.0f;
if (_audioAttack > BROW_LIFT_THRESHOLD) {
_browAudioLift += sqrtf(_audioAttack) * 0.01f;
}
_browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f);
const float BLINK_SPEED = 10.0f;
const float BLINK_SPEED_VARIABILITY = 1.0f;
const float BLINK_START_VARIABILITY = 0.25f;
@ -182,23 +185,23 @@ void Head::simulate(float deltaTime, bool isMine) {
} else {
_leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
_rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
if (_leftEyeBlink == FULLY_CLOSED) {
_leftEyeBlinkVelocity = -BLINK_SPEED;
} else if (_leftEyeBlink == FULLY_OPEN) {
_leftEyeBlinkVelocity = 0.0f;
}
if (_rightEyeBlink == FULLY_CLOSED) {
_rightEyeBlinkVelocity = -BLINK_SPEED;
} else if (_rightEyeBlink == FULLY_OPEN) {
_rightEyeBlinkVelocity = 0.0f;
}
}
// use data to update fake Faceshift blendshape coefficients
calculateMouthShapes();
calculateMouthShapes(deltaTime);
DependencyManager::get<Faceshift>()->updateFakeCoefficients(_leftEyeBlink,
_rightEyeBlink,
_browAudioLift,
@ -216,7 +219,7 @@ void Head::simulate(float deltaTime, bool isMine) {
if (Menu::getInstance()->isOptionChecked(MenuOption::FixGaze)) { // if debug menu turns off, use no saccade
_saccade = glm::vec3();
}
_leftEyePosition = _rightEyePosition = getPosition();
_eyePosition = getPosition();
@ -230,7 +233,7 @@ void Head::simulate(float deltaTime, bool isMine) {
_eyePosition = calculateAverageEyePosition();
}
void Head::calculateMouthShapes() {
void Head::calculateMouthShapes(float deltaTime) {
const float JAW_OPEN_SCALE = 0.015f;
const float JAW_OPEN_RATE = 0.9f;
const float JAW_CLOSE_RATE = 0.90f;
@ -242,20 +245,24 @@ void Head::calculateMouthShapes() {
const float SMILE_SPEED = 1.0f;
const float FUNNEL_SPEED = 2.335f;
const float STOP_GAIN = 5.0f;
const float NORMAL_HZ = 60.0f; // the update rate the constant values were tuned for
float deltaTimeRatio = deltaTime / (1.0f / NORMAL_HZ);
// From the change in loudness, decide how much to open or close the jaw
float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE;
if (audioDelta > _audioJawOpen) {
_audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE;
_audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE * deltaTimeRatio;
} else {
_audioJawOpen *= JAW_CLOSE_RATE;
_audioJawOpen *= powf(JAW_CLOSE_RATE, deltaTimeRatio);
}
_audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f);
_trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f);
float trailingAudioJawOpenRatio = (100.0f - deltaTime * NORMAL_HZ) / 100.0f; // --> 0.99 at 60 Hz
_trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, trailingAudioJawOpenRatio);
// Advance time at a rate proportional to loudness, and move the mouth shapes through
// Advance time at a rate proportional to loudness, and move the mouth shapes through
// a cycle at differing speeds to create a continuous random blend of shapes.
_mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT;
_mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT * deltaTimeRatio;
_mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN);
_mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN);
_mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN);
@ -321,7 +328,7 @@ glm::quat Head::getFinalOrientationInLocalFrame() const {
//
// Everyone else's head also keeps track of a correctedLookAtPosition that may be different for the same head within
// different Interfaces. If that head is not looking at me, the correctedLookAtPosition is the same as the lookAtPosition.
// However, if that head is looking at me, then I will attempt to adjust the lookAtPosition by the difference between
// However, if that head is looking at me, then I will attempt to adjust the lookAtPosition by the difference between
// my (singular) eye position and my actual camera position. This adjustment is used on their eyeballs during rendering
// (and also on any lookAt vector display for that head, during rendering). Note that:
// 1. this adjustment can be made directly to the other head's eyeball joints, because we won't be send their joint information to others.

View file

@ -138,7 +138,7 @@ private:
int _rightEyeLookAtID;
// private methods
void calculateMouthShapes();
void calculateMouthShapes(float timeRatio);
void applyEyelidOffset(glm::quat headOrientation);
};

View file

@ -1345,6 +1345,45 @@ controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const {
return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
}
void MyAvatar::setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) {
if (controller::InputDevice::getLowVelocityFilter()) {
auto oldLeftPose = getLeftFootControllerPoseInSensorFrame();
auto oldRightPose = getRightFootControllerPoseInSensorFrame();
_leftFootControllerPoseInSensorFrameCache.set(applyLowVelocityFilter(oldLeftPose, left));
_rightFootControllerPoseInSensorFrameCache.set(applyLowVelocityFilter(oldRightPose, right));
} else {
_leftFootControllerPoseInSensorFrameCache.set(left);
_rightFootControllerPoseInSensorFrameCache.set(right);
}
}
controller::Pose MyAvatar::getLeftFootControllerPoseInSensorFrame() const {
return _leftFootControllerPoseInSensorFrameCache.get();
}
controller::Pose MyAvatar::getRightFootControllerPoseInSensorFrame() const {
return _rightFootControllerPoseInSensorFrameCache.get();
}
controller::Pose MyAvatar::getLeftFootControllerPoseInWorldFrame() const {
return _leftFootControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
}
controller::Pose MyAvatar::getRightFootControllerPoseInWorldFrame() const {
return _rightFootControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
}
controller::Pose MyAvatar::getLeftFootControllerPoseInAvatarFrame() const {
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
return getLeftFootControllerPoseInWorldFrame().transform(invAvatarMatrix);
}
controller::Pose MyAvatar::getRightFootControllerPoseInAvatarFrame() const {
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
return getRightFootControllerPoseInWorldFrame().transform(invAvatarMatrix);
}
void MyAvatar::updateMotors() {
_characterController.clearMotors();
glm::quat motorRotation;

View file

@ -445,6 +445,14 @@ public:
controller::Pose getLeftHandControllerPoseInAvatarFrame() const;
controller::Pose getRightHandControllerPoseInAvatarFrame() const;
void setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
controller::Pose getLeftFootControllerPoseInSensorFrame() const;
controller::Pose getRightFootControllerPoseInSensorFrame() const;
controller::Pose getLeftFootControllerPoseInWorldFrame() const;
controller::Pose getRightFootControllerPoseInWorldFrame() const;
controller::Pose getLeftFootControllerPoseInAvatarFrame() const;
controller::Pose getRightFootControllerPoseInAvatarFrame() const;
bool hasDriveInput() const;
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled);
@ -684,6 +692,9 @@ private:
ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _leftFootControllerPoseInSensorFrameCache{ controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightFootControllerPoseInSensorFrameCache{ controller::Pose() };
bool _hmdLeanRecenterEnabled = true;
AnimPose _prePhysicsRoomPose;

View file

@ -132,31 +132,49 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->updateFromHeadParameters(headParams, deltaTime);
Rig::HandParameters handParams;
Rig::HandAndFeetParameters handAndFeetParams;
auto leftPose = myAvatar->getLeftHandControllerPoseInAvatarFrame();
if (leftPose.isValid()) {
handParams.isLeftEnabled = true;
handParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation();
handParams.leftOrientation = Quaternions::Y_180 * leftPose.getRotation();
handAndFeetParams.isLeftEnabled = true;
handAndFeetParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation();
handAndFeetParams.leftOrientation = Quaternions::Y_180 * leftPose.getRotation();
} else {
handParams.isLeftEnabled = false;
handAndFeetParams.isLeftEnabled = false;
}
auto rightPose = myAvatar->getRightHandControllerPoseInAvatarFrame();
if (rightPose.isValid()) {
handParams.isRightEnabled = true;
handParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation();
handParams.rightOrientation = Quaternions::Y_180 * rightPose.getRotation();
handAndFeetParams.isRightEnabled = true;
handAndFeetParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation();
handAndFeetParams.rightOrientation = Quaternions::Y_180 * rightPose.getRotation();
} else {
handParams.isRightEnabled = false;
handAndFeetParams.isRightEnabled = false;
}
handParams.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
handParams.bodyCapsuleHalfHeight = myAvatar->getCharacterController()->getCapsuleHalfHeight();
handParams.bodyCapsuleLocalOffset = myAvatar->getCharacterController()->getCapsuleLocalOffset();
auto leftFootPose = myAvatar->getLeftFootControllerPoseInAvatarFrame();
if (leftFootPose.isValid()) {
handAndFeetParams.isLeftFootEnabled = true;
handAndFeetParams.leftFootPosition = Quaternions::Y_180 * leftFootPose.getTranslation();
handAndFeetParams.leftFootOrientation = Quaternions::Y_180 * leftFootPose.getRotation();
} else {
handAndFeetParams.isLeftFootEnabled = false;
}
_rig->updateFromHandParameters(handParams, deltaTime);
auto rightFootPose = myAvatar->getRightFootControllerPoseInAvatarFrame();
if (rightFootPose.isValid()) {
handAndFeetParams.isRightFootEnabled = true;
handAndFeetParams.rightFootPosition = Quaternions::Y_180 * rightFootPose.getTranslation();
handAndFeetParams.rightFootOrientation = Quaternions::Y_180 * rightFootPose.getRotation();
} else {
handAndFeetParams.isRightFootEnabled = false;
}
handAndFeetParams.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
handAndFeetParams.bodyCapsuleHalfHeight = myAvatar->getCharacterController()->getCapsuleHalfHeight();
handAndFeetParams.bodyCapsuleLocalOffset = myAvatar->getCharacterController()->getCapsuleLocalOffset();
_rig->updateFromHandAndFeetParameters(handAndFeetParams, deltaTime);
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());

View file

@ -0,0 +1,26 @@
//
// FileTypeProfile.cpp
// interface/src/networking
//
// Created by Kunal Gosar on 2017-03-10.
// 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 "FileTypeProfile.h"
#include "FileTypeRequestInterceptor.h"
static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
FileTypeProfile::FileTypeProfile(QObject* parent) :
QQuickWebEngineProfile(parent)
{
static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
auto requestInterceptor = new FileTypeRequestInterceptor(this);
setRequestInterceptor(requestInterceptor);
}

View file

@ -0,0 +1,25 @@
//
// FileTypeProfile.h
// interface/src/networking
//
// Created by Kunal Gosar on 2017-03-10.
// 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
//
#pragma once
#ifndef hifi_FileTypeProfile_h
#define hifi_FileTypeProfile_h
#include <QtWebEngine/QQuickWebEngineProfile>
class FileTypeProfile : public QQuickWebEngineProfile {
public:
FileTypeProfile(QObject* parent = Q_NULLPTR);
};
#endif // hifi_FileTypeProfile_h

View file

@ -0,0 +1,21 @@
//
// FileTypeRequestInterceptor.cpp
// interface/src/networking
//
// Created by Kunal Gosar on 2017-03-10.
// 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 "FileTypeRequestInterceptor.h"
#include <QtCore/QDebug>
#include "RequestFilters.h"
void FileTypeRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
RequestFilters::interceptHFWebEngineRequest(info);
RequestFilters::interceptFileType(info);
}

View file

@ -0,0 +1,26 @@
//
// FileTypeRequestInterceptor.h
// interface/src/networking
//
// Created by Kunal Gosar on 2017-03-10.
// 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
//
#pragma once
#ifndef hifi_FileTypeRequestInterceptor_h
#define hifi_FileTypeRequestInterceptor_h
#include <QWebEngineUrlRequestInterceptor>
class FileTypeRequestInterceptor : public QWebEngineUrlRequestInterceptor {
public:
FileTypeRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
};
#endif // hifi_FileTypeRequestInterceptor_h

View file

@ -10,35 +10,12 @@
//
#include "HFWebEngineRequestInterceptor.h"
#include "NetworkingConstants.h"
#include <QtCore/QDebug>
#include <AccountManager.h>
bool isAuthableHighFidelityURL(const QUrl& url) {
static const QStringList HF_HOSTS = {
"highfidelity.com", "highfidelity.io",
"metaverse.highfidelity.com", "metaverse.highfidelity.io"
};
const auto& scheme = url.scheme();
const auto& host = url.host();
return (scheme == "https" && HF_HOSTS.contains(host)) ||
((scheme == NetworkingConstants::METAVERSE_SERVER_URL.scheme()) && (host == NetworkingConstants::METAVERSE_SERVER_URL.host()));
}
#include "RequestFilters.h"
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
// check if this is a request to a highfidelity URL
if (isAuthableHighFidelityURL(info.requestUrl())) {
// if we have an access token, add it to the right HTTP header for authorization
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->hasValidAccessToken()) {
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
}
}
RequestFilters::interceptHFWebEngineRequest(info);
}

View file

@ -0,0 +1,65 @@
//
// RequestFilters.cpp
// interface/src/networking
//
// Created by Kunal Gosar on 2017-03-10.
// 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 "RequestFilters.h"
#include "NetworkingConstants.h"
#include <QtCore/QDebug>
#include <AccountManager.h>
namespace {
bool isAuthableHighFidelityURL(const QUrl& url) {
static const QStringList HF_HOSTS = {
"highfidelity.com", "highfidelity.io",
"metaverse.highfidelity.com", "metaverse.highfidelity.io"
};
const auto& scheme = url.scheme();
const auto& host = url.host();
return (scheme == "https" && HF_HOSTS.contains(host)) ||
((scheme == NetworkingConstants::METAVERSE_SERVER_URL.scheme()) && (host == NetworkingConstants::METAVERSE_SERVER_URL.host()));
}
bool isScript(const QString filename) {
return filename.endsWith(".js", Qt::CaseInsensitive);
}
bool isJSON(const QString filename) {
return filename.endsWith(".json", Qt::CaseInsensitive);
}
}
void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) {
// check if this is a request to a highfidelity URL
if (isAuthableHighFidelityURL(info.requestUrl())) {
// if we have an access token, add it to the right HTTP header for authorization
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->hasValidAccessToken()) {
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
}
}
}
void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) {
QString filename = info.requestUrl().fileName();
if (isScript(filename) || isJSON(filename)) {
static const QString CONTENT_HEADER = "Accept";
static const QString TYPE_VALUE = "text/plain,text/html";
info.setHttpHeader(CONTENT_HEADER.toLocal8Bit(), TYPE_VALUE.toLocal8Bit());
}
}

View file

@ -0,0 +1,28 @@
//
// RequestFilters.h
// interface/src/networking
//
// Created by Kunal Gosar on 2017-03-10.
// 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
//
#pragma once
#ifndef hifi_RequestFilters_h
#define hifi_RequestFilters_h
#include <QObject>
#include <QWebEngineUrlRequestInfo>
class RequestFilters : public QObject {
Q_OBJECT
public:
static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info);
static void interceptFileType(QWebEngineUrlRequestInfo& info);
};
#endif // hifi_RequestFilters_h

View file

@ -31,6 +31,7 @@
#include "TabletScriptingInterface.h"
#include "scripting/HMDScriptingInterface.h"
static const QVariant TABLET_ADDRESS_DIALOG = "TabletAddressDialog.qml";
template<typename T>
void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
if (!member) {
@ -46,12 +47,48 @@ void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
}
void DialogsManager::toggleAddressBar() {
AddressBarDialog::toggle();
emit addressBarToggled();
auto hmd = DependencyManager::get<HMDScriptingInterface>();
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode()) {
if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG)) {
tablet->gotoHomeScreen();
emit addressBarToggled();
} else {
tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
emit addressBarToggled();
}
} else {
if (hmd->getShouldShowTablet()) {
if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG) && _closeAddressBar) {
tablet->gotoHomeScreen();
hmd->closeTablet();
_closeAddressBar = false;
emit addressBarToggled();
} else {
tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
_closeAddressBar = true;
emit addressBarToggled();
}
} else {
tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
hmd->openTablet();
_closeAddressBar = true;
emit addressBarToggled();
}
}
}
void DialogsManager::showAddressBar() {
AddressBarDialog::show();
auto hmd = DependencyManager::get<HMDScriptingInterface>();
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
if (!hmd->getShouldShowTablet()) {
hmd->openTablet();
}
}
void DialogsManager::showFeed() {

View file

@ -79,6 +79,7 @@ private:
QPointer<OctreeStatsDialog> _octreeStatsDialog;
QPointer<TestingDialog> _testingDialog;
QPointer<DomainConnectionDialog> _domainConnectionDialog;
bool _closeAddressBar { false };
};
#endif // hifi_DialogsManager_h

View file

@ -76,8 +76,8 @@ void JSConsole::setScriptEngine(ScriptEngine* scriptEngine) {
return;
}
if (_scriptEngine != NULL) {
disconnect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&)));
disconnect(_scriptEngine, SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&)));
disconnect(_scriptEngine, &ScriptEngine::printedMessage, this, &JSConsole::handlePrint);
disconnect(_scriptEngine, &ScriptEngine::errorMessage, this, &JSConsole::handleError);
if (_ownScriptEngine) {
_scriptEngine->deleteLater();
}
@ -87,8 +87,8 @@ void JSConsole::setScriptEngine(ScriptEngine* scriptEngine) {
_ownScriptEngine = scriptEngine == NULL;
_scriptEngine = _ownScriptEngine ? DependencyManager::get<ScriptEngines>()->loadScript(QString(), false) : scriptEngine;
connect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&)));
connect(_scriptEngine, SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&)));
connect(_scriptEngine, &ScriptEngine::printedMessage, this, &JSConsole::handlePrint);
connect(_scriptEngine, &ScriptEngine::errorMessage, this, &JSConsole::handleError);
}
void JSConsole::executeCommand(const QString& command) {
@ -134,11 +134,13 @@ void JSConsole::commandFinished() {
resetCurrentCommandHistory();
}
void JSConsole::handleError(const QString& message) {
void JSConsole::handleError(const QString& scriptName, const QString& message) {
Q_UNUSED(scriptName);
appendMessage(GUTTER_ERROR, "<span style='" + RESULT_ERROR_STYLE + "'>" + message.toHtmlEscaped() + "</span>");
}
void JSConsole::handlePrint(const QString& message) {
void JSConsole::handlePrint(const QString& scriptName, const QString& message) {
Q_UNUSED(scriptName);
appendMessage("", message);
}

View file

@ -47,8 +47,8 @@ protected:
protected slots:
void scrollToBottom();
void resizeTextInput();
void handlePrint(const QString& message);
void handleError(const QString& message);
void handlePrint(const QString& scriptName, const QString& message);
void handleError(const QString& scriptName, const QString& message);
void commandFinished();
private:

View file

@ -199,9 +199,9 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
pendingChanges.updateItem(itemID);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
}
}
@ -264,9 +264,9 @@ void Base3DOverlay::locationChanged(bool tellPhysics) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
pendingChanges.updateItem(itemID);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
}

View file

@ -58,15 +58,15 @@ void ModelOverlay::update(float deltatime) {
_isLoaded = _model->isActive();
}
bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
Volume3DOverlay::addToScene(overlay, scene, pendingChanges);
_model->addToScene(scene, pendingChanges);
bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
Volume3DOverlay::addToScene(overlay, scene, transaction);
_model->addToScene(scene, transaction);
return true;
}
void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
Volume3DOverlay::removeFromScene(overlay, scene, pendingChanges);
_model->removeFromScene(scene, pendingChanges);
void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
Volume3DOverlay::removeFromScene(overlay, scene, transaction);
_model->removeFromScene(scene, transaction);
}
void ModelOverlay::render(RenderArgs* args) {
@ -74,16 +74,16 @@ void ModelOverlay::render(RenderArgs* args) {
// check to see if when we added our model to the scene they were ready, if they were not ready, then
// fix them up in the scene
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
render::Transaction transaction;
if (_model->needsFixupInScene()) {
_model->removeFromScene(scene, pendingChanges);
_model->addToScene(scene, pendingChanges);
_model->removeFromScene(scene, transaction);
_model->addToScene(scene, transaction);
}
_model->setVisibleInScene(_visible, scene);
_model->setLayeredInFront(getDrawInFront(), scene);
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
void ModelOverlay::setProperties(const QVariantMap& properties) {

View file

@ -36,8 +36,8 @@ public:
virtual ModelOverlay* createClone() const override;
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
void locationChanged(bool tellPhysics) override;

View file

@ -196,14 +196,14 @@ float Overlay::updatePulse() {
return _pulse;
}
bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
_renderItemID = scene->allocateID();
pendingChanges.resetItem(_renderItemID, std::make_shared<Overlay::Payload>(overlay));
transaction.resetItem(_renderItemID, std::make_shared<Overlay::Payload>(overlay));
return true;
}
void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemID);
void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
transaction.removeItem(_renderItemID);
render::Item::clearID(_renderItemID);
}

View file

@ -48,8 +48,8 @@ public:
virtual AABox getBounds() const = 0;
virtual bool supportsGetProperty() const { return true; }
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction);
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::Transaction& transaction);
virtual const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); }

View file

@ -78,7 +78,7 @@ void Overlays::update(float deltatime) {
void Overlays::cleanupOverlaysToDelete() {
if (!_overlaysToDelete.isEmpty()) {
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
render::Transaction transaction;
{
QWriteLocker lock(&_deleteLock);
@ -88,13 +88,13 @@ void Overlays::cleanupOverlaysToDelete() {
auto itemID = overlay->getRenderItemID();
if (render::Item::isValidID(itemID)) {
overlay->removeFromScene(overlay, scene, pendingChanges);
overlay->removeFromScene(overlay, scene, transaction);
}
} while (!_overlaysToDelete.isEmpty());
}
if (pendingChanges._removedItems.size() > 0) {
scene->enqueuePendingChanges(pendingChanges);
if (transaction._removedItems.size() > 0) {
scene->enqueueTransaction(transaction);
}
}
}
@ -197,9 +197,9 @@ OverlayID Overlays::addOverlay(Overlay::Pointer overlay) {
_overlaysWorld[thisID] = overlay;
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
overlay->addToScene(overlay, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
overlay->addToScene(overlay, scene, transaction);
scene->enqueueTransaction(transaction);
} else {
_overlaysHUD[thisID] = overlay;
}

View file

@ -74,7 +74,7 @@ void AnimationReader::run() {
// Parse the FBX directly from the QNetworkReply
FBXGeometry::Pointer fbxgeo;
if (_url.path().toLower().endsWith(".fbx")) {
fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path()));
fbxgeo.reset(readFBX(_data, QVariantHash(), _url));
} else {
QString errorStr("usupported format");
emit onError(299, errorStr);

View file

@ -1146,9 +1146,8 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
}
}
void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, float dt) {
if (_animSkeleton && _animNode) {
const float HAND_RADIUS = 0.05f;
int hipsIndex = indexOfJoint("Hips");
glm::vec3 hipsTrans;
@ -1197,6 +1196,27 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
_animVars.unset("rightHandRotation");
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
if (params.isLeftFootEnabled) {
_animVars.set("leftFootPosition", params.leftFootPosition);
_animVars.set("leftFootRotation", params.leftFootOrientation);
_animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
} else {
_animVars.unset("leftFootPosition");
_animVars.unset("leftFootRotation");
_animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
}
if (params.isRightFootEnabled) {
_animVars.set("rightFootPosition", params.rightFootPosition);
_animVars.set("rightFootRotation", params.rightFootOrientation);
_animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
} else {
_animVars.unset("rightFootPosition");
_animVars.unset("rightFootRotation");
_animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
}
}
}

View file

@ -60,7 +60,7 @@ public:
int rightEyeJointIndex = -1;
};
struct HandParameters {
struct HandAndFeetParameters {
bool isLeftEnabled;
bool isRightEnabled;
float bodyCapsuleRadius;
@ -70,6 +70,13 @@ public:
glm::quat leftOrientation = glm::quat(); // rig space (z forward)
glm::vec3 rightPosition = glm::vec3(); // rig space
glm::quat rightOrientation = glm::quat(); // rig space (z forward)
bool isLeftFootEnabled;
bool isRightFootEnabled;
glm::vec3 leftFootPosition = glm::vec3(); // rig space
glm::quat leftFootOrientation = glm::quat(); // rig space (z forward)
glm::vec3 rightFootPosition = glm::vec3(); // rig space
glm::quat rightFootOrientation = glm::quat(); // rig space (z forward)
};
enum class CharacterControllerState {
@ -185,7 +192,7 @@ public:
void updateFromHeadParameters(const HeadParameters& params, float dt);
void updateFromEyeParameters(const EyeParameters& params);
void updateFromHandParameters(const HandParameters& params, float dt);
void updateFromHandAndFeetParameters(const HandAndFeetParameters& params, float dt);
void initAnimGraph(const QUrl& url);

View file

@ -51,6 +51,8 @@ namespace controller {
makePosePair(Action::LEFT_HAND, "LeftHand"),
makePosePair(Action::RIGHT_HAND, "RightHand"),
makePosePair(Action::LEFT_FOOT, "LeftFoot"),
makePosePair(Action::RIGHT_FOOT, "RightFoot"),
makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"),
makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"),

View file

@ -42,6 +42,8 @@ enum class Action {
LEFT_HAND = NUM_COMBINED_AXES,
RIGHT_HAND,
LEFT_FOOT,
RIGHT_FOOT,
LEFT_HAND_CLICK,
RIGHT_HAND_CLICK,

View file

@ -102,6 +102,8 @@ Input::NamedVector StandardController::getAvailableInputs() const {
// Poses
makePair(LEFT_HAND, "LeftHand"),
makePair(RIGHT_HAND, "RightHand"),
makePair(LEFT_FOOT, "LeftFoot"),
makePair(RIGHT_FOOT, "RightFoot"),
// Aliases, PlayStation style names
makePair(LB, "L1"),

View file

@ -158,6 +158,22 @@ namespace controller {
LEFT_HAND_PINKY2,
LEFT_HAND_PINKY3,
LEFT_HAND_PINKY4,
TRACKED_OBJECT_00,
TRACKED_OBJECT_01,
TRACKED_OBJECT_02,
TRACKED_OBJECT_03,
TRACKED_OBJECT_04,
TRACKED_OBJECT_05,
TRACKED_OBJECT_06,
TRACKED_OBJECT_07,
TRACKED_OBJECT_08,
TRACKED_OBJECT_09,
TRACKED_OBJECT_10,
TRACKED_OBJECT_11,
TRACKED_OBJECT_12,
TRACKED_OBJECT_13,
TRACKED_OBJECT_14,
TRACKED_OBJECT_15,
NUM_STANDARD_POSES
};

View file

@ -571,10 +571,15 @@ void OpenGLDisplayPlugin::compositeLayers() {
compositeScene();
}
#ifdef HIFI_ENABLE_NSIGHT_DEBUG
if (false) // do not compositeoverlay if running nsight debug
#endif
{
PROFILE_RANGE_EX(render_detail, "compositeOverlay", 0xff0077ff, (uint64_t)presentCount())
compositeOverlay();
}
auto compositorHelper = DependencyManager::get<CompositorHelper>();
if (compositorHelper->getReticleVisible()) {
PROFILE_RANGE_EX(render_detail, "compositePointer", 0xff0077ff, (uint64_t)presentCount())

View file

@ -127,11 +127,11 @@ void EntityTreeRenderer::clear() {
// remove all entities from the scene
auto scene = _viewState->getMain3DScene();
if (scene) {
render::PendingChanges pendingChanges;
render::Transaction transaction;
foreach(auto entity, _entitiesInScene) {
entity->removeFromScene(entity, scene, pendingChanges);
entity->removeFromScene(entity, scene, transaction);
}
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
} else {
qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown";
}
@ -951,11 +951,11 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
// here's where we remove the entity payload from the scene
if (_entitiesInScene.contains(entityID)) {
auto entity = _entitiesInScene.take(entityID);
render::PendingChanges pendingChanges;
render::Transaction transaction;
auto scene = _viewState->getMain3DScene();
if (scene) {
entity->removeFromScene(entity, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
entity->removeFromScene(entity, scene, transaction);
scene->enqueueTransaction(transaction);
} else {
qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), Unexpected null scene, possibly during application shutdown";
}
@ -973,13 +973,13 @@ void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
// here's where we add the entity payload to the scene
render::PendingChanges pendingChanges;
render::Transaction transaction;
auto scene = _viewState->getMain3DScene();
if (scene) {
if (entity->addToScene(entity, scene, pendingChanges)) {
if (entity->addToScene(entity, scene, transaction)) {
_entitiesInScene.insert(entity->getEntityItemID(), entity);
}
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
} else {
qCWarning(entitiesrenderer) << "EntityTreeRenderer::addEntityToScene(), Unexpected null scene, possibly during application shutdown";
}

View file

@ -54,7 +54,7 @@ namespace render {
// Mixin class for implementing basic single item rendering
class SimpleRenderableEntityItem {
public:
bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
_myItem = scene->allocateID();
auto renderData = std::make_shared<RenderableEntityItemProxy>(self, _myItem);
@ -64,13 +64,13 @@ public:
makeEntityItemStatusGetters(self, statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_myItem, renderPayload);
transaction.resetItem(_myItem, renderPayload);
return true;
}
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myItem);
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
transaction.removeItem(_myItem);
render::Item::clearID(_myItem);
}
@ -79,14 +79,14 @@ public:
return;
}
render::PendingChanges pendingChanges;
render::Transaction transaction;
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
if (scene) {
pendingChanges.updateItem<RenderableEntityItemProxy>(_myItem, [](RenderableEntityItemProxy& data) {
transaction.updateItem<RenderableEntityItemProxy>(_myItem, [](RenderableEntityItemProxy& data) {
});
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
} else {
qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown";
}
@ -99,8 +99,8 @@ private:
#define SIMPLE_RENDERABLE() \
public: \
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { return _renderHelper.addToScene(self, scene, pendingChanges); } \
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override { return _renderHelper.addToScene(self, scene, transaction); } \
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override { _renderHelper.removeFromScene(self, scene, transaction); } \
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); _renderHelper.notifyChanged(); } \
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); _renderHelper.notifyChanged(); } \
void checkFading() { \

View file

@ -27,7 +27,7 @@ RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityI
{
}
bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
_myItem = scene->allocateID();
auto renderItem = std::make_shared<LightPayload>();
@ -39,7 +39,7 @@ bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_p
makeEntityItemStatusGetters(self, statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_myItem, renderPayload);
transaction.resetItem(_myItem, renderPayload);
return true;
}
@ -51,8 +51,8 @@ void RenderableLightEntityItem::somethingChangedNotification() {
LightEntityItem::somethingChangedNotification();
}
void RenderableLightEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myItem);
void RenderableLightEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) {
transaction.removeItem(_myItem);
render::Item::clearID(_myItem);
}
@ -81,12 +81,12 @@ void RenderableLightEntityItem::notifyChanged() {
return;
}
render::PendingChanges pendingChanges;
render::Transaction transaction;
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
updateLightFromEntity(pendingChanges);
updateLightFromEntity(transaction);
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@ -103,13 +103,13 @@ bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& ori
}
void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pendingChanges) {
void RenderableLightEntityItem::updateLightFromEntity(render::Transaction& transaction) {
if (!render::Item::isValidID(_myItem)) {
return;
}
pendingChanges.updateItem<LightPayload>(_myItem, [&](LightPayload& data) {
transaction.updateItem<LightPayload>(_myItem, [&](LightPayload& data) {
updateRenderItemFromEntity(data);
});
}

View file

@ -28,12 +28,12 @@ public:
BoxFace& face, glm::vec3& surfaceNormal,
void** intersectedObject, bool precisionPicking) const override;
void updateLightFromEntity(render::PendingChanges& pendingChanges);
void updateLightFromEntity(render::Transaction& transaction);
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
virtual void somethingChangedNotification() override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
virtual void locationChanged(bool tellPhysics = true) override;

View file

@ -228,20 +228,20 @@ namespace render {
}
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
render::Transaction& transaction) {
_myMetaItem = scene->allocateID();
auto renderData = std::make_shared<RenderableModelEntityItemMeta>(self);
auto renderPayload = std::make_shared<RenderableModelEntityItemMeta::Payload>(renderData);
pendingChanges.resetItem(_myMetaItem, renderPayload);
transaction.resetItem(_myMetaItem, renderPayload);
if (_model) {
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
// note: we don't mind if the model fails to add, we'll retry (in render()) until it succeeds
_model->addToScene(scene, pendingChanges, statusGetters);
_model->addToScene(scene, transaction, statusGetters);
}
// we've successfully added _myMetaItem so we always return true
@ -249,11 +249,11 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
}
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myMetaItem);
render::Transaction& transaction) {
transaction.removeItem(_myMetaItem);
render::Item::clearID(_myMetaItem);
if (_model) {
_model->removeFromScene(scene, pendingChanges);
_model->removeFromScene(scene, transaction);
}
}
@ -277,10 +277,11 @@ bool RenderableModelEntityItem::getAnimationFrame() {
return false;
}
if (_animation && _animation->isLoaded()) {
auto animation = getAnimation();
if (animation && animation->isLoaded()) {
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
auto& fbxJoints = _animation->getGeometry().joints;
const QVector<FBXAnimationFrame>& frames = animation->getFramesReference(); // NOTE: getFrames() is too heavy
auto& fbxJoints = animation->getGeometry().joints;
int frameCount = frames.size();
if (frameCount > 0) {
@ -467,15 +468,15 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
}
if (_model->needsFixupInScene()) {
render::PendingChanges pendingChanges;
render::Transaction transaction;
_model->removeFromScene(scene, pendingChanges);
_model->removeFromScene(scene, transaction);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
_model->addToScene(scene, pendingChanges, statusGetters);
_model->addToScene(scene, transaction, statusGetters);
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
auto& currentURL = getParsedModelURL();
@ -525,9 +526,9 @@ ModelPointer RenderableModelEntityItem::getModel(QSharedPointer<EntityTreeRender
} else if (_model) {
// remove from scene
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
_model->removeFromScene(scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
_model->removeFromScene(scene, transaction);
scene->enqueueTransaction(transaction);
// release interest
_myRenderer->releaseModel(_model);
@ -566,7 +567,7 @@ void RenderableModelEntityItem::update(const quint64& now) {
}
// make a copy of the animation properites
_renderAnimationProperties = _animationProperties;
_renderAnimationProperties = getAnimationProperties();
ModelEntityItem::update(now);
}
@ -608,11 +609,11 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
void RenderableModelEntityItem::setShapeType(ShapeType type) {
ModelEntityItem::setShapeType(type);
if (_shapeType == SHAPE_TYPE_COMPOUND) {
if (!_compoundShapeResource && !_compoundShapeURL.isEmpty()) {
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
if (!_compoundShapeResource && !getCompoundShapeURL().isEmpty()) {
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(getCompoundShapeURL());
}
} else if (_compoundShapeResource && !_compoundShapeURL.isEmpty()) {
} else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) {
// the compoundURL has been set but the shapeType does not agree
_compoundShapeResource.reset();
}
@ -627,7 +628,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
if (tree) {
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
}
if (_shapeType == SHAPE_TYPE_COMPOUND) {
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(url);
}
}
@ -637,7 +638,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
ShapeType type = getShapeType();
if (type == SHAPE_TYPE_COMPOUND) {
if (!_model || _compoundShapeURL.isEmpty()) {
if (!_model || getCompoundShapeURL().isEmpty()) {
EntityTreePointer tree = getTree();
if (tree) {
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
@ -659,8 +660,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
doInitialModelSimulation();
}
return true;
} else if (!_compoundShapeURL.isEmpty()) {
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(_compoundShapeURL);
} else if (!getCompoundShapeURL().isEmpty()) {
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(getCompoundShapeURL());
}
}
@ -775,7 +776,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + _model->getOffset()) - registrationOffset;
}
}
shapeInfo.setParams(type, dimensions, _compoundShapeURL);
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
// should never fall in here when model not fully loaded
assert(_model && _model->isLoaded());
@ -1001,7 +1002,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
}
}
shapeInfo.setParams(type, 0.5f * dimensions, _modelURL);
shapeInfo.setParams(type, 0.5f * dimensions, getModelURL());
} else {
ModelEntityItem::computeShapeInfo(shapeInfo);
shapeInfo.setParams(type, 0.5f * dimensions);
@ -1226,10 +1227,10 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
}
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
render::Transaction transaction;
pendingChanges.updateItem(myMetaItem);
scene->enqueuePendingChanges(pendingChanges);
transaction.updateItem(myMetaItem);
scene->enqueueTransaction(transaction);
});
}
}

View file

@ -40,8 +40,8 @@ public:
void doInitialModelSimulation();
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
void updateModelBounds();

View file

@ -162,7 +162,7 @@ RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const Ent
bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
render::ScenePointer scene,
render::PendingChanges& pendingChanges) {
render::Transaction& transaction) {
_scene = scene;
_renderItemId = _scene->allocateID();
auto particlePayloadData = std::make_shared<ParticlePayloadData>();
@ -171,14 +171,14 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_renderItemId, renderPayload);
transaction.resetItem(_renderItemId, renderPayload);
return true;
}
void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self,
render::ScenePointer scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemId);
render::Transaction& transaction) {
transaction.removeItem(_renderItemId);
_scene = nullptr;
render::Item::clearID(_renderItemId);
};
@ -206,12 +206,12 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
return;
}
if (!getVisible()) {
render::PendingChanges pendingChanges;
pendingChanges.updateItem<ParticlePayloadData>(_renderItemId, [](ParticlePayloadData& payload) {
render::Transaction transaction;
transaction.updateItem<ParticlePayloadData>(_renderItemId, [](ParticlePayloadData& payload) {
payload.setVisibleFlag(false);
});
_scene->enqueuePendingChanges(pendingChanges);
_scene->enqueueTransaction(transaction);
return;
}
@ -253,8 +253,8 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
}
render::PendingChanges pendingChanges;
pendingChanges.updateItem<ParticlePayloadData>(_renderItemId, [=](ParticlePayloadData& payload) {
render::Transaction transaction;
transaction.updateItem<ParticlePayloadData>(_renderItemId, [=](ParticlePayloadData& payload) {
payload.setVisibleFlag(true);
// Update particle uniforms
@ -282,7 +282,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
}
});
_scene->enqueuePendingChanges(pendingChanges);
_scene->enqueueTransaction(transaction);
}
void RenderableParticleEffectEntityItem::createPipelines() {
@ -318,9 +318,9 @@ void RenderableParticleEffectEntityItem::notifyBoundChanged() {
if (!render::Item::isValidID(_renderItemId)) {
return;
}
render::PendingChanges pendingChanges;
pendingChanges.updateItem<ParticlePayloadData>(_renderItemId, [](ParticlePayloadData& payload) {
render::Transaction transaction;
transaction.updateItem<ParticlePayloadData>(_renderItemId, [](ParticlePayloadData& payload) {
});
_scene->enqueuePendingChanges(pendingChanges);
_scene->enqueueTransaction(transaction);
}

View file

@ -25,8 +25,8 @@ public:
void updateRenderItem();
virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override;
virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::Transaction& transaction) override;
virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::Transaction& transaction) override;
protected:
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }

View file

@ -660,22 +660,22 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
});
}
void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) {
if (xTextureURL != _xTextureURL) {
void RenderablePolyVoxEntityItem::setXTextureURL(const QString& xTextureURL) {
if (xTextureURL != getXTextureURL()) {
_xTexture.clear();
PolyVoxEntityItem::setXTextureURL(xTextureURL);
}
}
void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) {
if (yTextureURL != _yTextureURL) {
void RenderablePolyVoxEntityItem::setYTextureURL(const QString& yTextureURL) {
if (yTextureURL != getYTextureURL()) {
_yTexture.clear();
PolyVoxEntityItem::setYTextureURL(yTextureURL);
}
}
void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) {
if (zTextureURL != _zTextureURL) {
void RenderablePolyVoxEntityItem::setZTextureURL(const QString& zTextureURL) {
if (zTextureURL != getZTextureURL()) {
_zTexture.clear();
PolyVoxEntityItem::setZTextureURL(zTextureURL);
}
@ -817,7 +817,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
render::Transaction& transaction) {
_myItem = scene->allocateID();
auto renderItem = std::make_shared<PolyVoxPayload>(getThisPointer());
@ -828,15 +828,15 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_myItem, renderPayload);
transaction.resetItem(_myItem, renderPayload);
return true;
}
void RenderablePolyVoxEntityItem::removeFromScene(EntityItemPointer self,
std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myItem);
render::Transaction& transaction) {
transaction.removeItem(_myItem);
render::Item::clearID(_myItem);
}
@ -1615,10 +1615,10 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
return;
}
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
pendingChanges.updateItem<PolyVoxPayload>(_myItem, [](PolyVoxPayload& payload) {});
render::Transaction transaction;
transaction.updateItem<PolyVoxPayload>(_myItem, [](PolyVoxPayload& payload) {});
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
}
bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {

View file

@ -101,16 +101,16 @@ public:
virtual bool setAll(uint8_t toValue) override;
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) override;
virtual void setXTextureURL(QString xTextureURL) override;
virtual void setYTextureURL(QString yTextureURL) override;
virtual void setZTextureURL(QString zTextureURL) override;
virtual void setXTextureURL(const QString& xTextureURL) override;
virtual void setYTextureURL(const QString& yTextureURL) override;
virtual void setZTextureURL(const QString& zTextureURL) override;
virtual bool addToScene(EntityItemPointer self,
std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) override;
render::Transaction& transaction) override;
virtual void removeFromScene(EntityItemPointer self,
std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) override;
render::Transaction& transaction) override;
virtual void setXNNeighborID(const EntityItemID& xNNeighborID) override;
virtual void setYNNeighborID(const EntityItemID& yNNeighborID) override;

View file

@ -77,14 +77,16 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
geometryCache->bindSimpleProgram(batch, false, transparent, false, false, true);
geometryCache->renderQuad(batch, minCorner, maxCorner, backgroundColor, _geometryID);
float scale = _lineHeight / _textRenderer->getFontSize();
float lineheight = getLineHeight();
float scale = lineheight / _textRenderer->getFontSize();
transformToTopLeft.setScale(scale); // Scale to have the correct line height
batch.setModelTransform(transformToTopLeft);
float leftMargin = 0.1f * _lineHeight, topMargin = 0.1f * _lineHeight;
float leftMargin = 0.1f * lineheight, topMargin = 0.1f * lineheight;
glm::vec2 bounds = glm::vec2(dimensions.x - 2.0f * leftMargin,
dimensions.y - 2.0f * topMargin);
_textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, _text, textColor, bounds / scale);
auto text = getText();
_textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, text, textColor, bounds / scale);
}

View file

@ -266,7 +266,7 @@ void RenderableWebEntityItem::loadSourceURL() {
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
}
_webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) {
_webSurface->load("WebEntityView.qml", [&](QQmlContext* context, QObject* obj) {
context->setContextProperty("eventBridgeJavaScriptToInject", QVariant(_javaScriptToInject));
});

View file

@ -118,13 +118,13 @@ void RenderableZoneEntityItem::render(RenderArgs* args) {
// check to see if when we added our models to the scene they were ready, if they were not ready, then
// fix them up in the scene
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
_model->removeFromScene(scene, pendingChanges);
render::Transaction transaction;
_model->removeFromScene(scene, transaction);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
_model->addToScene(scene, pendingChanges);
_model->addToScene(scene, transaction);
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
_model->setVisibleInScene(getVisible(), scene);
}
@ -164,9 +164,9 @@ void RenderableZoneEntityItem::render(RenderArgs* args) {
_model && !_model->needsFixupInScene()) {
// If the model is in the scene but doesn't need to be, remove it.
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
_model->removeFromScene(scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
render::Transaction transaction;
_model->removeFromScene(scene, transaction);
scene->enqueueTransaction(transaction);
}
}
@ -218,7 +218,7 @@ namespace render {
}
bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
render::Transaction& transaction) {
_myMetaItem = scene->allocateID();
auto renderData = std::make_shared<RenderableZoneEntityItemMeta>(self);
@ -228,16 +228,16 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_myMetaItem, renderPayload);
transaction.resetItem(_myMetaItem, renderPayload);
return true;
}
void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myMetaItem);
render::Transaction& transaction) {
transaction.removeItem(_myMetaItem);
render::Item::clearID(_myMetaItem);
if (_model) {
_model->removeFromScene(scene, pendingChanges);
_model->removeFromScene(scene, transaction);
}
}
@ -246,13 +246,13 @@ void RenderableZoneEntityItem::notifyBoundChanged() {
if (!render::Item::isValidID(_myMetaItem)) {
return;
}
render::PendingChanges pendingChanges;
render::Transaction transaction;
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
if (scene) {
pendingChanges.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
transaction.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
});
scene->enqueuePendingChanges(pendingChanges);
scene->enqueueTransaction(transaction);
} else {
qCWarning(entitiesrenderer) << "RenderableZoneEntityItem::notifyBoundChanged(), Unexpected null scene, possibly during application shutdown";
}

View file

@ -38,8 +38,8 @@ public:
virtual void render(RenderArgs* args) override;
virtual bool contains(const glm::vec3& point) const override;
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
private:
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }

View file

@ -683,7 +683,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// However, for now, when the server uses a newer time than what we sent, listen to what we're told.
if (overwriteLocalData) weOwnSimulation = false;
} else if (_simulationOwner.set(newSimOwner)) {
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
// recompute weOwnSimulation for later
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
@ -695,19 +695,19 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
weOwnSimulation = true;
if (!_simulationOwner.isNull()) {
// someone else really did own it
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
_simulationOwner.clearCurrentOwner();
}
} else if (newSimOwner.matchesValidID(myNodeID) && !_hasBidOnSimulation) {
// entity-server tells us that we have simulation ownership while we never requested this for this EntityItem,
// this could happen when the user reloads the cache and entity tree.
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
_simulationOwner.clearCurrentOwner();
weOwnSimulation = false;
} else if (_simulationOwner.set(newSimOwner)) {
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
// recompute weOwnSimulation for later
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
@ -909,19 +909,23 @@ void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSk
float EntityItem::computeMass() const {
glm::vec3 dimensions = getDimensions();
return _density * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
return getDensity() * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
}
void EntityItem::setDensity(float density) {
_density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
withWriteLock([&] {
_density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
});
}
void EntityItem::updateDensity(float density) {
float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
if (_density != clampedDensity) {
_density = clampedDensity;
_dirtyFlags |= Simulation::DIRTY_MASS;
}
withWriteLock([&] {
if (_density != clampedDensity) {
_density = clampedDensity;
_dirtyFlags |= Simulation::DIRTY_MASS;
}
});
}
void EntityItem::setMass(float mass) {
@ -941,10 +945,12 @@ void EntityItem::setMass(float mass) {
} else {
newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
}
if (_density != newDensity) {
_density = newDensity;
_dirtyFlags |= Simulation::DIRTY_MASS;
}
withWriteLock([&] {
if (_density != newDensity) {
_density = newDensity;
_dirtyFlags |= Simulation::DIRTY_MASS;
}
});
}
void EntityItem::setHref(QString value) {
@ -952,32 +958,47 @@ void EntityItem::setHref(QString value) {
if (! (value.toLower().startsWith("hifi://")) ) {
return;
}
_href = value;
withWriteLock([&] {
_href = value;
});
}
void EntityItem::setCollisionSoundURL(const QString& value) {
if (_collisionSoundURL != value) {
_collisionSoundURL = value;
bool modified = false;
withWriteLock([&] {
if (_collisionSoundURL != value) {
_collisionSoundURL = value;
modified = true;
}
});
if (modified) {
if (auto myTree = getTree()) {
myTree->notifyNewCollisionSoundURL(_collisionSoundURL, getEntityItemID());
myTree->notifyNewCollisionSoundURL(value, getEntityItemID());
}
}
}
SharedSoundPointer EntityItem::getCollisionSound() {
if (!_collisionSound) {
_collisionSound = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
SharedSoundPointer result;
withReadLock([&] {
result = _collisionSound;
});
if (!result) {
result = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
withWriteLock([&] {
_collisionSound = result;
});
}
return _collisionSound;
return result;
}
void EntityItem::simulate(const quint64& now) {
if (_lastSimulated == 0) {
_lastSimulated = now;
if (getLastSimulated() == 0) {
setLastSimulated(now);
}
float timeElapsed = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND);
float timeElapsed = (float)(now - getLastSimulated()) / (float)(USECS_PER_SECOND);
#ifdef WANT_DEBUG
qCDebug(entities) << "********** EntityItem::simulate()";
@ -1021,10 +1042,10 @@ void EntityItem::simulate(const quint64& now) {
if (!stepKinematicMotion(timeElapsed)) {
// this entity is no longer moving
// flag it to transition from KINEMATIC to STATIC
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
markDirtyFlags(Simulation::DIRTY_MOTION_TYPE);
setAcceleration(Vectors::ZERO);
}
_lastSimulated = now;
setLastSimulated(now);
}
bool EntityItem::stepKinematicMotion(float timeElapsed) {
@ -1056,9 +1077,10 @@ bool EntityItem::stepKinematicMotion(float timeElapsed) {
timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED);
if (isSpinning) {
float angularDamping = getAngularDamping();
// angular damping
if (_angularDamping > 0.0f) {
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
if (angularDamping > 0.0f) {
angularVelocity *= powf(1.0f - angularDamping, timeElapsed);
}
const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED =
@ -1086,15 +1108,17 @@ bool EntityItem::stepKinematicMotion(float timeElapsed) {
glm::vec3 deltaVelocity = Vectors::ZERO;
// linear damping
if (_damping > 0.0f) {
deltaVelocity = (powf(1.0f - _damping, timeElapsed) - 1.0f) * linearVelocity;
float damping = getDamping();
if (damping > 0.0f) {
deltaVelocity = (powf(1.0f - damping, timeElapsed) - 1.0f) * linearVelocity;
}
const float MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED = 1.0e-4f; // 0.01 m/sec^2
if (glm::length2(_acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) {
vec3 acceleration = getAcceleration();
if (glm::length2(acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) {
// yes acceleration
// acceleration is in world-frame but we need it in local-frame
glm::vec3 linearAcceleration = _acceleration;
glm::vec3 linearAcceleration = acceleration;
bool success;
Transform parentTransform = getParentTransform(success);
if (success) {
@ -1180,7 +1204,7 @@ bool EntityItem::lifetimeHasExpired() const {
}
quint64 EntityItem::getExpiry() const {
return _created + (quint64)(_lifetime * (float)USECS_PER_SECOND);
return getCreated() + (quint64)(getLifetime() * (float)USECS_PER_SECOND);
}
EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
@ -1189,10 +1213,10 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
EntityItemProperties properties(propertyFlags);
properties._id = getID();
properties._idSet = true;
properties._created = _created;
properties._lastEdited = _lastEdited;
properties.setClientOnly(_clientOnly);
properties.setOwningAvatarID(_owningAvatarID);
properties._created = getCreated();
properties._lastEdited = getLastEdited();
properties.setClientOnly(getClientOnly());
properties.setOwningAvatarID(getOwningAvatarID());
properties._type = getType();
@ -1259,7 +1283,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
properties._angularVelocity = getLocalAngularVelocity();
}
if (!properties._accelerationChanged) {
properties._acceleration = _acceleration;
properties._acceleration = getAcceleration();
}
properties._positionChanged = true;
@ -1270,7 +1294,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
}
void EntityItem::pokeSimulationOwnership() {
_dirtyFlags |= Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE;
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE);
auto nodeList = DependencyManager::get<NodeList>();
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
// we already own it
@ -1282,7 +1306,7 @@ void EntityItem::pokeSimulationOwnership() {
}
void EntityItem::grabSimulationOwnership() {
_dirtyFlags |= Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB;
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB);
auto nodeList = DependencyManager::get<NodeList>();
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
// we already own it
@ -1575,18 +1599,18 @@ float EntityItem::getVolumeEstimate() const {
void EntityItem::updateRegistrationPoint(const glm::vec3& value) {
if (value != _registrationPoint) {
setRegistrationPoint(value);
_dirtyFlags |= Simulation::DIRTY_SHAPE;
markDirtyFlags(Simulation::DIRTY_SHAPE);
}
}
void EntityItem::updatePosition(const glm::vec3& value) {
if (getLocalPosition() != value) {
setLocalPosition(value);
_dirtyFlags |= Simulation::DIRTY_POSITION;
markDirtyFlags(Simulation::DIRTY_POSITION);
forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->_dirtyFlags |= Simulation::DIRTY_POSITION;
entity->markDirtyFlags(Simulation::DIRTY_POSITION);
}
});
}
@ -1595,8 +1619,9 @@ void EntityItem::updatePosition(const glm::vec3& value) {
void EntityItem::updateParentID(const QUuid& value) {
if (getParentID() != value) {
setParentID(value);
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; // children are forced to be kinematic
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
// children are forced to be kinematic
// may need to not collide with own avatar
markDirtyFlags(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_COLLISION_GROUP);
}
}
@ -1610,7 +1635,7 @@ void EntityItem::updatePositionFromNetwork(const glm::vec3& value) {
void EntityItem::updateDimensions(const glm::vec3& value) {
if (getDimensions() != value) {
setDimensions(value);
_dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
}
}
@ -1621,8 +1646,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) {
forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->_dirtyFlags |= Simulation::DIRTY_ROTATION;
entity->_dirtyFlags |= Simulation::DIRTY_POSITION;
entity->markDirtyFlags(Simulation::DIRTY_ROTATION | Simulation::DIRTY_POSITION);
}
});
}
@ -1777,20 +1801,26 @@ void EntityItem::updateRestitution(float value) {
void EntityItem::updateFriction(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION);
if (_friction != clampedValue) {
_friction = clampedValue;
_dirtyFlags |= Simulation::DIRTY_MATERIAL;
}
withWriteLock([&] {
if (_friction != clampedValue) {
_friction = clampedValue;
_dirtyFlags |= Simulation::DIRTY_MATERIAL;
}
});
}
void EntityItem::setRestitution(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION);
_restitution = clampedValue;
withWriteLock([&] {
_restitution = clampedValue;
});
}
void EntityItem::setFriction(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION);
_friction = clampedValue;
withWriteLock([&] {
_friction = clampedValue;
});
}
void EntityItem::updateLifetime(float value) {
@ -1883,7 +1913,7 @@ void EntityItem::updateSimulationOwner(const SimulationOwner& owner) {
}
if (_simulationOwner.set(owner)) {
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
}
}
@ -1896,7 +1926,7 @@ void EntityItem::clearSimulationOwnership() {
// don't bother setting the DIRTY_SIMULATOR_ID flag because:
// (a) when entity-server calls clearSimulationOwnership() the dirty-flags are meaningless (only used by interface)
// (b) the interface only calls clearSimulationOwnership() in a context that already knows best about dirty flags
//_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
//markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
}
@ -2103,7 +2133,7 @@ void EntityItem::deserializeActionsInternal() {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex(".*action creation failed for.*");
qCDebug(entities) << "EntityItem::deserializeActionsInternal -- action creation failed for"
<< getID() << getName();
<< getID() << _name; // getName();
removeActionInternal(actionID, nullptr);
}
}
@ -2327,3 +2357,443 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const {
// the json filter syntax did not match what we expected, return a match
return true;
}
quint64 EntityItem::getLastSimulated() const {
quint64 result;
withReadLock([&] {
result = _lastSimulated;
});
return result;
}
void EntityItem::setLastSimulated(quint64 now) {
withWriteLock([&] {
_lastSimulated = now;
});
}
quint64 EntityItem::getLastEdited() const {
quint64 result;
withReadLock([&] {
result = _lastEdited;
});
return result;
}
void EntityItem::setLastEdited(quint64 lastEdited) {
withWriteLock([&] {
_lastEdited = _lastUpdated = lastEdited;
_changedOnServer = glm::max(lastEdited, _changedOnServer);
});
}
quint64 EntityItem::getLastBroadcast() const {
quint64 result;
withReadLock([&] {
result = _lastBroadcast;
});
return result;
}
void EntityItem::setLastBroadcast(quint64 lastBroadcast) {
withWriteLock([&] {
_lastBroadcast = lastBroadcast;
});
}
void EntityItem::markAsChangedOnServer() {
withWriteLock([&] {
_changedOnServer = usecTimestampNow();
});
}
quint64 EntityItem::getLastChangedOnServer() const {
quint64 result;
withReadLock([&] {
result = _changedOnServer;
});
return result;
}
void EntityItem::update(const quint64& now) {
withWriteLock([&] {
_lastUpdated = now;
});
}
quint64 EntityItem::getLastUpdated() const {
quint64 result;
withReadLock([&] {
result = _lastUpdated;
});
return result;
}
void EntityItem::requiresRecalcBoxes() {
withWriteLock([&] {
_recalcAABox = true;
_recalcMinAACube = true;
_recalcMaxAACube = true;
});
}
QString EntityItem::getHref() const {
QString result;
withReadLock([&] {
result = _href;
});
return result;
}
QString EntityItem::getDescription() const {
QString result;
withReadLock([&] {
result = _description;
});
return result;
}
void EntityItem::setDescription(const QString& value) {
withWriteLock([&] {
_description = value;
});
}
float EntityItem::getLocalRenderAlpha() const {
float result;
withReadLock([&] {
result = _localRenderAlpha;
});
return result;
}
void EntityItem::setLocalRenderAlpha(float localRenderAlpha) {
withWriteLock([&] {
_localRenderAlpha = localRenderAlpha;
});
}
glm::vec3 EntityItem::getGravity() const {
glm::vec3 result;
withReadLock([&] {
result = _gravity;
});
return result;
}
void EntityItem::setGravity(const glm::vec3& value) {
withWriteLock([&] {
_gravity = value;
});
}
glm::vec3 EntityItem::getAcceleration() const {
glm::vec3 result;
withReadLock([&] {
result = _acceleration;
});
return result;
}
void EntityItem::setAcceleration(const glm::vec3& value) {
withWriteLock([&] {
_acceleration = value;
});
}
float EntityItem::getDamping() const {
float result;
withReadLock([&] {
result = _damping;
});
return result;
}
void EntityItem::setDamping(float value) {
withWriteLock([&] {
_damping = value;
});
}
float EntityItem::getRestitution() const {
float result;
withReadLock([&] {
result = _restitution;
});
return result;
}
float EntityItem::getFriction() const {
float result;
withReadLock([&] {
result = _friction;
});
return result;
}
// lifetime related properties.
float EntityItem::getLifetime() const {
float result;
withReadLock([&] {
result = _lifetime;
});
return result;
}
void EntityItem::setLifetime(float value) {
withWriteLock([&] {
_lifetime = value;
});
}
quint64 EntityItem::getCreated() const {
quint64 result;
withReadLock([&] {
result = _created;
});
return result;
}
void EntityItem::setCreated(quint64 value) {
withWriteLock([&] {
_created = value;
});
}
QString EntityItem::getScript() const {
QString result;
withReadLock([&] {
result = _script;
});
return result;
}
void EntityItem::setScript(const QString& value) {
withWriteLock([&] {
_script = value;
});
}
quint64 EntityItem::getScriptTimestamp() const {
quint64 result;
withReadLock([&] {
result = _scriptTimestamp;
});
return result;
}
void EntityItem::setScriptTimestamp(const quint64 value) {
withWriteLock([&] {
_scriptTimestamp = value;
});
}
QString EntityItem::getServerScripts() const {
QString result;
withReadLock([&] {
result = _serverScripts;
});
return result;
}
void EntityItem::setServerScripts(const QString& serverScripts) {
withWriteLock([&] {
_serverScripts = serverScripts;
_serverScriptsChangedTimestamp = usecTimestampNow();
});
}
QString EntityItem::getCollisionSoundURL() const {
QString result;
withReadLock([&] {
result = _collisionSoundURL;
});
return result;
}
void EntityItem::setCollisionSound(SharedSoundPointer sound) {
withWriteLock([&] {
_collisionSound = sound;
});
}
glm::vec3 EntityItem::getRegistrationPoint() const {
glm::vec3 result;
withReadLock([&] {
result = _registrationPoint;
});
return result;
}
void EntityItem::setRegistrationPoint(const glm::vec3& value) {
withWriteLock([&] {
_registrationPoint = glm::clamp(value, 0.0f, 1.0f);
});
dimensionsChanged(); // Registration Point affects the bounding box
}
float EntityItem::getAngularDamping() const {
float result;
withReadLock([&] {
result = _angularDamping;
});
return result;
}
void EntityItem::setAngularDamping(float value) {
withWriteLock([&] {
_angularDamping = value;
});
}
QString EntityItem::getName() const {
QString result;
withReadLock([&] {
result = _name;
});
return result;
}
void EntityItem::setName(const QString& value) {
withWriteLock([&] {
_name = value;
});
}
QString EntityItem::getDebugName() {
QString result = getName();
if (result.isEmpty()) {
result = getID().toString();
}
return result;
}
bool EntityItem::getVisible() const {
bool result;
withReadLock([&] {
result = _visible;
});
return result;
}
void EntityItem::setVisible(bool value) {
withWriteLock([&] {
_visible = value;
});
}
bool EntityItem::getCollisionless() const {
bool result;
withReadLock([&] {
result = _collisionless;
});
return result;
}
void EntityItem::setCollisionless(bool value) {
withWriteLock([&] {
_collisionless = value;
});
}
uint8_t EntityItem::getCollisionMask() const {
uint8_t result;
withReadLock([&] {
result = _collisionMask;
});
return result;
}
void EntityItem::setCollisionMask(uint8_t value) {
withWriteLock([&] {
_collisionMask = value;
});
}
bool EntityItem::getDynamic() const {
if (SHAPE_TYPE_STATIC_MESH == getShapeType()) {
return false;
}
bool result;
withReadLock([&] {
result = _dynamic;
});
return result;
}
void EntityItem::setDynamic(bool value) {
withWriteLock([&] {
_dynamic = value;
});
}
bool EntityItem::getLocked() const {
bool result;
withReadLock([&] {
result = _locked;
});
return result;
}
void EntityItem::setLocked(bool value) {
withWriteLock([&] {
_locked = value;
});
}
QString EntityItem::getUserData() const {
QString result;
withReadLock([&] {
result = _userData;
});
return result;
}
void EntityItem::setUserData(const QString& value) {
withWriteLock([&] {
_userData = value;
});
}
QString EntityItem::getMarketplaceID() const {
QString result;
withReadLock([&] {
result = _marketplaceID;
});
return result;
}
void EntityItem::setMarketplaceID(const QString& value) {
withWriteLock([&] {
_marketplaceID = value;
});
}
uint32_t EntityItem::getDirtyFlags() const {
uint32_t result;
withReadLock([&] {
result = _dirtyFlags;
});
return result;
}
void EntityItem::markDirtyFlags(uint32_t mask) {
withWriteLock([&] {
_dirtyFlags |= mask;
});
}
void EntityItem::clearDirtyFlags(uint32_t mask) {
withWriteLock([&] {
_dirtyFlags &= ~mask;
});
}
float EntityItem::getDensity() const {
float result;
withReadLock([&] {
result = _density;
});
return result;
}

View file

@ -53,7 +53,7 @@ using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElemen
namespace render {
class Scene;
class PendingChanges;
class Transaction;
}
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
@ -110,22 +110,21 @@ public:
virtual void somethingChangedNotification() { }
void recordCreationTime(); // set _created to 'now'
quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs
void setLastSimulated(quint64 now) { _lastSimulated = now; }
quint64 getLastSimulated() const; /// Last simulated time of this entity universal usecs
void setLastSimulated(quint64 now);
/// Last edited time of this entity universal usecs
quint64 getLastEdited() const { return _lastEdited; }
void setLastEdited(quint64 lastEdited)
{ _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); }
quint64 getLastEdited() const;
void setLastEdited(quint64 lastEdited);
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
/// Last time we sent out an edit packet for this entity
quint64 getLastBroadcast() const { return _lastBroadcast; }
void setLastBroadcast(quint64 lastBroadcast) { _lastBroadcast = lastBroadcast; }
quint64 getLastBroadcast() const;
void setLastBroadcast(quint64 lastBroadcast);
void markAsChangedOnServer() { _changedOnServer = usecTimestampNow(); }
quint64 getLastChangedOnServer() const { return _changedOnServer; }
void markAsChangedOnServer();
quint64 getLastChangedOnServer() const;
// TODO: eventually only include properties changed since the params.lastQuerySent time
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
@ -153,9 +152,9 @@ public:
{ somethingChanged = false; return 0; }
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene
render::Transaction& transaction) { return false; } // by default entity items don't add to scene
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) { } // by default entity items don't add to scene
render::Transaction& transaction) { } // by default entity items don't add to scene
virtual void render(RenderArgs* args) { } // by default entity items don't know how to render
static int expectedBytes();
@ -163,8 +162,8 @@ public:
static void adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSkew);
// perform update
virtual void update(const quint64& now) { _lastUpdated = now; }
quint64 getLastUpdated() const { return _lastUpdated; }
virtual void update(const quint64& now);
quint64 getLastUpdated() const;
// perform linear extrapolation for SimpleEntitySimulation
void simulate(const quint64& now);
@ -188,63 +187,63 @@ public:
const Transform getTransformToCenter(bool& success) const;
inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; }
inline void requiresRecalcBoxes();
// Hyperlink related getters and setters
QString getHref() const { return _href; }
QString getHref() const;
void setHref(QString value);
QString getDescription() const { return _description; }
void setDescription(QString value) { _description = value; }
QString getDescription() const;
void setDescription(const QString& value);
/// Dimensions in meters (0.0 - TREE_SCALE)
inline const glm::vec3 getDimensions() const { return getScale(); }
virtual void setDimensions(const glm::vec3& value);
float getLocalRenderAlpha() const { return _localRenderAlpha; }
void setLocalRenderAlpha(float localRenderAlpha) { _localRenderAlpha = localRenderAlpha; }
float getLocalRenderAlpha() const;
void setLocalRenderAlpha(float localRenderAlpha);
void setDensity(float density);
float computeMass() const;
void setMass(float mass);
float getDensity() const { return _density; }
float getDensity() const;
bool hasVelocity() const { return getVelocity() != ENTITY_ITEM_ZERO_VEC3; }
bool hasLocalVelocity() const { return getLocalVelocity() != ENTITY_ITEM_ZERO_VEC3; }
const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
glm::vec3 getGravity() const; /// get gravity in meters
void setGravity(const glm::vec3& value); /// gravity in meters
bool hasGravity() const { return getGravity() != ENTITY_ITEM_ZERO_VEC3; }
const glm::vec3& getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second
void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second
bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; }
glm::vec3 getAcceleration() const; /// get acceleration in meters/second/second
void setAcceleration(const glm::vec3& value); /// acceleration in meters/second/second
bool hasAcceleration() const { return getAcceleration() != ENTITY_ITEM_ZERO_VEC3; }
float getDamping() const { return _damping; }
void setDamping(float value) { _damping = value; }
float getDamping() const;
void setDamping(float value);
float getRestitution() const { return _restitution; }
float getRestitution() const;
void setRestitution(float value);
float getFriction() const { return _friction; }
float getFriction() const;
void setFriction(float value);
// lifetime related properties.
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
float getLifetime() const; /// get the lifetime in seconds for the entity
void setLifetime(float value); /// set the lifetime in seconds for the entity
quint64 getCreated() const { return _created; } /// get the created-time in useconds for the entity
void setCreated(quint64 value) { _created = value; } /// set the created-time in useconds for the entity
quint64 getCreated() const; /// get the created-time in useconds for the entity
void setCreated(quint64 value); /// set the created-time in useconds for the entity
/// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted
bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; }
bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; }
/// is this entity mortal, in that it has a lifetime set, and will automatically be deleted when that lifetime expires
bool isMortal() const { return _lifetime != ENTITY_ITEM_IMMORTAL_LIFETIME; }
bool isMortal() const { return getLifetime() != ENTITY_ITEM_IMMORTAL_LIFETIME; }
/// age of this entity in seconds
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
float getAge() const { return (float)(usecTimestampNow() - getCreated()) / (float)USECS_PER_SECOND; }
bool lifetimeHasExpired() const;
quint64 getExpiry() const;
@ -256,63 +255,61 @@ public:
using SpatiallyNestable::getQueryAACube;
virtual AACube getQueryAACube(bool& success) const override;
QString getScript() const { return _script; }
void setScript(const QString& value) { _script = value; }
QString getScript() const;
void setScript(const QString& value);
quint64 getScriptTimestamp() const { return _scriptTimestamp; }
void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; }
quint64 getScriptTimestamp() const;
void setScriptTimestamp(const quint64 value);
QString getServerScripts() const { return _serverScripts; }
void setServerScripts(const QString& serverScripts)
{ _serverScripts = serverScripts; _serverScriptsChangedTimestamp = usecTimestampNow(); }
QString getServerScripts() const;
void setServerScripts(const QString& serverScripts);
const QString& getCollisionSoundURL() const { return _collisionSoundURL; }
QString getCollisionSoundURL() const;
void setCollisionSoundURL(const QString& value);
SharedSoundPointer getCollisionSound();
void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; }
void setCollisionSound(SharedSoundPointer sound);
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity
glm::vec3 getRegistrationPoint() const; /// registration point as ratio of entity
/// registration point as ratio of entity
void setRegistrationPoint(const glm::vec3& value) {
_registrationPoint = glm::clamp(value, 0.0f, 1.0f); dimensionsChanged(); // Registration Point affects the bounding box
}
void setRegistrationPoint(const glm::vec3& value);
bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; }
bool hasLocalAngularVelocity() const { return getLocalAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; }
float getAngularDamping() const { return _angularDamping; }
void setAngularDamping(float value) { _angularDamping = value; }
float getAngularDamping() const;
void setAngularDamping(float value);
QString getName() const { return _name; }
void setName(const QString& value) { _name = value; }
QString getDebugName() { return _name != "" ? _name : getID().toString(); }
QString getName() const;
void setName(const QString& value);
QString getDebugName();
bool getVisible() const { return _visible; }
void setVisible(bool value) { _visible = value; }
bool isVisible() const { return _visible; }
bool isInvisible() const { return !_visible; }
bool getVisible() const;
void setVisible(bool value);
inline bool isVisible() const { return getVisible(); }
inline bool isInvisible() const { return !getVisible(); }
bool getCollisionless() const { return _collisionless; }
void setCollisionless(bool value) { _collisionless = value; }
bool getCollisionless() const;
void setCollisionless(bool value);
uint8_t getCollisionMask() const { return _collisionMask; }
void setCollisionMask(uint8_t value) { _collisionMask = value; }
uint8_t getCollisionMask() const;
void setCollisionMask(uint8_t value);
void computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const;
bool getDynamic() const { return SHAPE_TYPE_STATIC_MESH == getShapeType() ? false : _dynamic; }
void setDynamic(bool value) { _dynamic = value; }
bool getDynamic() const;
void setDynamic(bool value);
virtual bool shouldBePhysical() const { return false; }
bool getLocked() const { return _locked; }
void setLocked(bool value) { _locked = value; }
bool getLocked() const;
void setLocked(bool value);
const QString& getUserData() const { return _userData; }
virtual void setUserData(const QString& value) { _userData = value; }
QString getUserData() const;
virtual void setUserData(const QString& value);
// FIXME not thread safe?
const SimulationOwner& getSimulationOwner() const { return _simulationOwner; }
void setSimulationOwner(const QUuid& id, quint8 priority);
void setSimulationOwner(const SimulationOwner& owner);
@ -325,8 +322,8 @@ public:
void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp);
void rememberHasSimulationOwnershipBid() const;
const QString& getMarketplaceID() const { return _marketplaceID; }
void setMarketplaceID(const QString& value) { _marketplaceID = value; }
QString getMarketplaceID() const;
void setMarketplaceID(const QString& value);
// TODO: get rid of users of getRadius()...
float getRadius() const;
@ -369,8 +366,9 @@ public:
void updateCreated(uint64_t value);
virtual void setShapeType(ShapeType type) { /* do nothing */ }
uint32_t getDirtyFlags() const { return _dirtyFlags; }
void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; }
uint32_t getDirtyFlags() const;
void markDirtyFlags(uint32_t mask);
void clearDirtyFlags(uint32_t mask = 0xffffffff);
bool isMoving() const;
bool isMovingRelativeToParent() const;

View file

@ -182,6 +182,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
if (!wantsLocked) {
EntityItemProperties tempProperties;
tempProperties.setLocked(wantsLocked);
tempProperties.setLastEdited(properties.getLastEdited());
bool success;
AACube queryCube = entity->getQueryAACube(success);

View file

@ -69,38 +69,59 @@ EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredP
}
void LightEntityItem::setFalloffRadius(float value) {
_falloffRadius = glm::max(value, 0.0f);
_lightPropertiesChanged = true;
value = glm::max(value, 0.0f);
if (value == getFalloffRadius()) {
return;
}
withWriteLock([&] {
_falloffRadius = value;
_lightPropertiesChanged = true;
});
}
void LightEntityItem::setIsSpotlight(bool value) {
if (value != _isSpotlight) {
_isSpotlight = value;
glm::vec3 dimensions = getDimensions();
if (_isSpotlight) {
const float length = dimensions.z;
const float width = length * glm::sin(glm::radians(_cutoff));
setDimensions(glm::vec3(width, width, length));
} else {
float maxDimension = glm::compMax(dimensions);
setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
}
_lightPropertiesChanged = true;
if (value == getIsSpotlight()) {
return;
}
glm::vec3 dimensions = getDimensions();
glm::vec3 newDimensions;
if (value) {
const float length = dimensions.z;
const float width = length * glm::sin(glm::radians(getCutoff()));
newDimensions = glm::vec3(width, width, length);
} else {
newDimensions = glm::vec3(glm::compMax(dimensions));
}
withWriteLock([&] {
_isSpotlight = value;
_lightPropertiesChanged = true;
});
setDimensions(newDimensions);
}
void LightEntityItem::setCutoff(float value) {
_cutoff = glm::clamp(value, 0.0f, 90.0f);
value = glm::clamp(value, 0.0f, 90.0f);
if (value == getCutoff()) {
return;
}
if (_isSpotlight) {
withWriteLock([&] {
_cutoff = 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 width = length * glm::sin(glm::radians(_cutoff));
setDimensions(glm::vec3(width, width, length));
}
_lightPropertiesChanged = true;
withWriteLock([&] {
_lightPropertiesChanged = true;
});
}
bool LightEntityItem::setProperties(const EntityItemProperties& properties) {
@ -205,5 +226,86 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
void LightEntityItem::somethingChangedNotification() {
EntityItem::somethingChangedNotification();
_lightPropertiesChanged = false;
withWriteLock([&] {
_lightPropertiesChanged = false;
});
}
const rgbColor& LightEntityItem::getColor() const {
return _color;
}
xColor LightEntityItem::getXColor() const {
xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color;
}
void LightEntityItem::setColor(const rgbColor& value) {
withWriteLock([&] {
memcpy(_color, value, sizeof(_color));
_lightPropertiesChanged = true;
});
}
void LightEntityItem::setColor(const xColor& value) {
withWriteLock([&] {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
_lightPropertiesChanged = true;
});
}
bool LightEntityItem::getIsSpotlight() const {
bool result;
withReadLock([&] {
result = _isSpotlight;
});
return result;
}
float LightEntityItem::getIntensity() const {
float result;
withReadLock([&] {
result = _intensity;
});
return result;
}
void LightEntityItem::setIntensity(float value) {
withWriteLock([&] {
_intensity = value;
_lightPropertiesChanged = true;
});
}
float LightEntityItem::getFalloffRadius() const {
float result;
withReadLock([&] {
result = _falloffRadius;
});
return result;
}
float LightEntityItem::getExponent() const {
float result;
withReadLock([&] {
result = _exponent;
});
return result;
}
void LightEntityItem::setExponent(float value) {
withWriteLock([&] {
_exponent = value;
_lightPropertiesChanged = true;
});
}
float LightEntityItem::getCutoff() const {
float result;
withReadLock([&] {
result = _cutoff;
});
return result;
}

View file

@ -57,47 +57,33 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
const rgbColor& getColor() const { return _color; }
xColor getXColor() const {
xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color;
}
const rgbColor& getColor() const;
xColor getXColor() const;
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
_lightPropertiesChanged = true;
}
void setColor(const rgbColor& value);
void setColor(const xColor& value);
bool getIsSpotlight() const { return _isSpotlight; }
bool getIsSpotlight() const;
void setIsSpotlight(bool value);
void setIgnoredColor(const rgbColor& value) { }
void setIgnoredAttenuation(float value) { }
float getIntensity() const { return _intensity; }
void setIntensity(float value) {
_intensity = value;
_lightPropertiesChanged = true;
}
float getFalloffRadius() const { return _falloffRadius; }
float getIntensity() const;
void setIntensity(float value);
float getFalloffRadius() const;
void setFalloffRadius(float value);
float getExponent() const { return _exponent; }
void setExponent(float value) {
_exponent = value;
_lightPropertiesChanged = true;
}
float getExponent() const;
void setExponent(float value);
float getCutoff() const { return _cutoff; }
float getCutoff() const;
void setCutoff(float value);
static bool getLightsArePickable() { return _lightsArePickable; }
static void setLightsArePickable(bool value) { _lightsArePickable = value; }
protected:
private:
// properties of a light
@ -108,6 +94,7 @@ protected:
float _exponent { DEFAULT_EXPONENT };
float _cutoff { DEFAULT_CUTOFF };
protected:
// Dirty flag turn true when either light properties is changing values.
// This gets back to false in the somethingChangedNotification() call
// Which is called after a setProperties() or a readEntitySubClassFromBUfferCall on the entity.

View file

@ -34,8 +34,8 @@ EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const En
LineEntityItem::LineEntityItem(const EntityItemID& entityItemID) :
EntityItem(entityItemID),
_lineWidth(DEFAULT_LINE_WIDTH),
_pointsChanged(true),
_points(QVector<glm::vec3>(0))
_points(QVector<glm::vec3>(0)),
_pointsChanged(true)
{
_type = EntityTypes::Line;
}
@ -88,8 +88,10 @@ bool LineEntityItem::appendPoint(const glm::vec3& point) {
qCDebug(entities) << "Point is outside entity's bounding box";
return false;
}
_points << point;
_pointsChanged = true;
withWriteLock([&] {
_points << point;
_pointsChanged = true;
});
return true;
}
@ -105,8 +107,11 @@ bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
return false;
}
}
_points = points;
_pointsChanged = true;
withWriteLock([&] {
_points = points;
_pointsChanged = true;
});
return true;
}
@ -159,3 +164,51 @@ void LineEntityItem::debugDump() const {
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}
const rgbColor& LineEntityItem::getColor() const {
return _color;
}
xColor LineEntityItem::getXColor() const {
xColor result;
withReadLock([&] {
result = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] };
});
return result;
}
void LineEntityItem::setColor(const rgbColor& value) {
withWriteLock([&] {
memcpy(_color, value, sizeof(_color));
});
}
void LineEntityItem::setColor(const xColor& value) {
withWriteLock([&] {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
});
}
void LineEntityItem::setLineWidth(float lineWidth) {
withWriteLock([&] {
_lineWidth = lineWidth;
});
}
float LineEntityItem::getLineWidth() const {
float result;
withReadLock([&] {
result = _lineWidth;
});
return result;
}
QVector<glm::vec3> LineEntityItem::getLinePoints() const {
QVector<glm::vec3> result;
withReadLock([&] {
result = _points;
});
return result;
}

View file

@ -42,23 +42,19 @@ class LineEntityItem : public EntityItem {
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
const rgbColor& getColor() const;
xColor getXColor() const;
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
}
void setColor(const rgbColor& value);
void setColor(const xColor& value);
void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
float getLineWidth() const{ return _lineWidth; }
void setLineWidth(float lineWidth);
float getLineWidth() const;
bool setLinePoints(const QVector<glm::vec3>& points);
bool appendPoint(const glm::vec3& point);
const QVector<glm::vec3>& getLinePoints() const{ return _points; }
QVector<glm::vec3> getLinePoints() const;
virtual ShapeType getShapeType() const override { return SHAPE_TYPE_NONE; }
@ -74,11 +70,12 @@ class LineEntityItem : public EntityItem {
static const float DEFAULT_LINE_WIDTH;
static const int MAX_POINTS_PER_LINE;
protected:
private:
rgbColor _color;
float _lineWidth;
bool _pointsChanged;
QVector<glm::vec3> _points;
protected:
bool _pointsChanged;
};
#endif // hifi_LineEntityItem_h

View file

@ -733,3 +733,20 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
_timeUntilNextEmit = 0.0f;
}
}
QString ParticleEffectEntityItem::getTextures() const {
QString result;
withReadLock([&] {
result = _textures;
});
return result;
}
void ParticleEffectEntityItem::setTextures(const QString& textures) {
withWriteLock([&] {
if (_textures != textures) {
_textures = textures;
_texturesChangedFlag = true;
}
});
}

View file

@ -205,13 +205,8 @@ public:
void computeAndUpdateDimensions();
static const QString DEFAULT_TEXTURES;
const QString& getTextures() const { return _textures; }
void setTextures(const QString& textures) {
if (_textures != textures) {
_textures = textures;
_texturesChangedFlag = true;
}
}
QString getTextures() const;
void setTextures(const QString& textures);
static const bool DEFAULT_EMITTER_SHOULD_TRAIL;
bool getEmitterShouldTrail() const { return _emitterShouldTrail; }

View file

@ -104,14 +104,18 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) {
bool PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
_strokeWidths = strokeWidths;
_strokeWidthsChanged = true;
withWriteLock([&] {
_strokeWidths = strokeWidths;
_strokeWidthsChanged = true;
});
return true;
}
bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
_normals = normals;
_normalsChanged = true;
withWriteLock([&] {
_normals = normals;
_normalsChanged = true;
});
return true;
}
@ -119,35 +123,39 @@ bool PolyLineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
if (points.size() > MAX_POINTS_PER_LINE) {
return false;
}
if (points.size() != _points.size()) {
_pointsChanged = true;
}
//Check to see if points actually changed. If they haven't, return before doing anything else
else if (points.size() == _points.size()) {
//same number of points, so now compare every point
for (int i = 0; i < points.size(); i++) {
if (points.at(i) != _points.at(i)){
_pointsChanged = true;
break;
bool result = false;
withWriteLock([&] {
//Check to see if points actually changed. If they haven't, return before doing anything else
if (points.size() != _points.size()) {
_pointsChanged = true;
} else if (points.size() == _points.size()) {
//same number of points, so now compare every point
for (int i = 0; i < points.size(); i++) {
if (points.at(i) != _points.at(i)) {
_pointsChanged = true;
break;
}
}
}
}
if (!_pointsChanged) {
return false;
}
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
glm::vec3 halfBox = getDimensions() * 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;
if (!_pointsChanged) {
return;
}
}
_points = points;
return true;
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
glm::vec3 halfBox = getDimensions() * 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;
}
}
_points = points;
result = true;
});
return result;
}
int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
@ -210,3 +218,45 @@ void PolyLineEntityItem::debugDump() const {
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}
QVector<glm::vec3> PolyLineEntityItem::getLinePoints() const {
QVector<glm::vec3> result;
withReadLock([&] {
result = _points;
});
return result;
}
QVector<glm::vec3> PolyLineEntityItem::getNormals() const {
QVector<glm::vec3> result;
withReadLock([&] {
result = _normals;
});
return result;
}
QVector<float> PolyLineEntityItem::getStrokeWidths() const {
QVector<float> result;
withReadLock([&] {
result = _strokeWidths;
});
return result;
}
QString PolyLineEntityItem::getTextures() const {
QString result;
withReadLock([&] {
result = _textures;
});
return result;
}
void PolyLineEntityItem::setTextures(const QString& textures) {
withWriteLock([&] {
if (_textures != textures) {
_textures = textures;
_texturesChangedFlag = true;
}
});
}

View file

@ -59,21 +59,16 @@ class PolyLineEntityItem : public EntityItem {
bool setLinePoints(const QVector<glm::vec3>& points);
bool appendPoint(const glm::vec3& point);
const QVector<glm::vec3>& getLinePoints() const{ return _points; }
QVector<glm::vec3> getLinePoints() const;
bool setNormals(const QVector<glm::vec3>& normals);
const QVector<glm::vec3>& getNormals() const{ return _normals; }
QVector<glm::vec3> getNormals() const;
bool setStrokeWidths(const QVector<float>& strokeWidths);
const QVector<float>& getStrokeWidths() const{ return _strokeWidths; }
QVector<float> getStrokeWidths() const;
const QString& getTextures() const { return _textures; }
void setTextures(const QString& textures) {
if (_textures != textures) {
_textures = textures;
_texturesChangedFlag = true;
}
}
QString getTextures() const;
void setTextures(const QString& textures);
virtual bool needsToCallUpdate() const override { return true; }

View file

@ -242,3 +242,129 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const {
});
return voxelDataCopy;
}
void PolyVoxEntityItem::setXTextureURL(const QString& xTextureURL) {
withWriteLock([&] {
_xTextureURL = xTextureURL;
});
}
QString PolyVoxEntityItem::getXTextureURL() const {
QString result;
withReadLock([&] {
result = _xTextureURL;
});
return result;
}
void PolyVoxEntityItem::setYTextureURL(const QString& yTextureURL) {
withWriteLock([&] {
_yTextureURL = yTextureURL;
});
}
QString PolyVoxEntityItem::getYTextureURL() const {
QString result;
withReadLock([&] {
result = _yTextureURL;
});
return result;
}
void PolyVoxEntityItem::setZTextureURL(const QString& zTextureURL) {
withWriteLock([&] {
_zTextureURL = zTextureURL;
});
}
QString PolyVoxEntityItem::getZTextureURL() const {
QString result;
withReadLock([&] {
result = _zTextureURL;
});
return result;
}
void PolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighborID) {
withWriteLock([&] {
_xNNeighborID = xNNeighborID;
});
}
EntityItemID PolyVoxEntityItem::getXNNeighborID() const {
EntityItemID result;
withReadLock([&] {
result = _xNNeighborID;
});
return result;
}
void PolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighborID) {
withWriteLock([&] {
_yNNeighborID = yNNeighborID;
});
}
EntityItemID PolyVoxEntityItem::getYNNeighborID() const {
EntityItemID result;
withReadLock([&] {
result = _yNNeighborID;
});
return result;
}
void PolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighborID) {
withWriteLock([&] {
_zNNeighborID = zNNeighborID;
});
}
EntityItemID PolyVoxEntityItem::getZNNeighborID() const {
EntityItemID result;
withReadLock([&] {
result = _zNNeighborID;
});
return result;
}
void PolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighborID) {
withWriteLock([&] {
_xPNeighborID = xPNeighborID;
});
}
EntityItemID PolyVoxEntityItem::getXPNeighborID() const {
EntityItemID result;
withReadLock([&] {
result = _xPNeighborID;
});
return result;
}
void PolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighborID) {
withWriteLock([&] {
_yPNeighborID = yPNeighborID;
});
}
EntityItemID PolyVoxEntityItem::getYPNeighborID() const {
EntityItemID result;
withReadLock([&] {
result = _yPNeighborID;
});
return result;
}
void PolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighborID) {
withWriteLock([&] {
_zPNeighborID = zPNeighborID;
});
}
EntityItemID PolyVoxEntityItem::getZPNeighborID() const {
EntityItemID result;
withReadLock([&] {
result = _zPNeighborID;
});
return result;
}

View file

@ -99,36 +99,36 @@ class PolyVoxEntityItem : public EntityItem {
static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16);
static const QString DEFAULT_X_TEXTURE_URL;
virtual void setXTextureURL(QString xTextureURL) { _xTextureURL = xTextureURL; }
virtual const QString& getXTextureURL() const { return _xTextureURL; }
virtual void setXTextureURL(const QString& xTextureURL);
QString getXTextureURL() const;
static const QString DEFAULT_Y_TEXTURE_URL;
virtual void setYTextureURL(QString yTextureURL) { _yTextureURL = yTextureURL; }
virtual const QString& getYTextureURL() const { return _yTextureURL; }
virtual void setYTextureURL(const QString& yTextureURL);
QString getYTextureURL() const;
static const QString DEFAULT_Z_TEXTURE_URL;
virtual void setZTextureURL(QString zTextureURL) { _zTextureURL = zTextureURL; }
virtual const QString& getZTextureURL() const { return _zTextureURL; }
virtual void setZTextureURL(const QString& zTextureURL);
QString getZTextureURL() const;
virtual void setXNNeighborID(const EntityItemID& xNNeighborID) { _xNNeighborID = xNNeighborID; }
void setXNNeighborID(const QString& xNNeighborID) { setXNNeighborID(QUuid(xNNeighborID)); }
virtual const EntityItemID& getXNNeighborID() const { return _xNNeighborID; }
virtual void setYNNeighborID(const EntityItemID& yNNeighborID) { _yNNeighborID = yNNeighborID; }
void setYNNeighborID(const QString& yNNeighborID) { setYNNeighborID(QUuid(yNNeighborID)); }
virtual const EntityItemID& getYNNeighborID() const { return _yNNeighborID; }
virtual void setZNNeighborID(const EntityItemID& zNNeighborID) { _zNNeighborID = zNNeighborID; }
void setZNNeighborID(const QString& zNNeighborID) { setZNNeighborID(QUuid(zNNeighborID)); }
virtual const EntityItemID& getZNNeighborID() const { return _zNNeighborID; }
virtual void setXNNeighborID(const EntityItemID& xNNeighborID);
void setXNNeighborID(const QString& xNNeighborID);
virtual EntityItemID getXNNeighborID() const;
virtual void setYNNeighborID(const EntityItemID& yNNeighborID);
void setYNNeighborID(const QString& yNNeighborID);
virtual EntityItemID getYNNeighborID() const;
virtual void setZNNeighborID(const EntityItemID& zNNeighborID);
void setZNNeighborID(const QString& zNNeighborID);
virtual EntityItemID getZNNeighborID() const;
virtual void setXPNeighborID(const EntityItemID& xPNeighborID) { _xPNeighborID = xPNeighborID; }
void setXPNeighborID(const QString& xPNeighborID) { setXPNeighborID(QUuid(xPNeighborID)); }
virtual const EntityItemID& getXPNeighborID() const { return _xPNeighborID; }
virtual void setYPNeighborID(const EntityItemID& yPNeighborID) { _yPNeighborID = yPNeighborID; }
void setYPNeighborID(const QString& yPNeighborID) { setYPNeighborID(QUuid(yPNeighborID)); }
virtual const EntityItemID& getYPNeighborID() const { return _yPNeighborID; }
virtual void setZPNeighborID(const EntityItemID& zPNeighborID) { _zPNeighborID = zPNeighborID; }
void setZPNeighborID(const QString& zPNeighborID) { setZPNeighborID(QUuid(zPNeighborID)); }
virtual const EntityItemID& getZPNeighborID() const { return _zPNeighborID; }
virtual void setXPNeighborID(const EntityItemID& xPNeighborID);
void setXPNeighborID(const QString& xPNeighborID);
virtual EntityItemID getXPNeighborID() const;
virtual void setYPNeighborID(const EntityItemID& yPNeighborID);
void setYPNeighborID(const QString& yPNeighborID);
virtual EntityItemID getYPNeighborID() const;
virtual void setZPNeighborID(const EntityItemID& zPNeighborID);
void setZPNeighborID(const QString& zPNeighborID);
virtual EntityItemID getZPNeighborID() const;
virtual void rebakeMesh() {};

View file

@ -141,3 +141,98 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
// FIXME - should set face and surfaceNormal
return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
}
void TextEntityItem::setText(const QString& value) {
withWriteLock([&] {
_text = value;
});
}
QString TextEntityItem::getText() const {
QString result;
withReadLock([&] {
result = _text;
});
return result;
}
void TextEntityItem::setLineHeight(float value) {
withWriteLock([&] {
_lineHeight = value;
});
}
float TextEntityItem::getLineHeight() const {
float result;
withReadLock([&] {
result = _lineHeight;
});
return result;
}
const rgbColor& TextEntityItem::getTextColor() const {
return _textColor;
}
const rgbColor& TextEntityItem::getBackgroundColor() const {
return _backgroundColor;
}
xColor TextEntityItem::getTextColorX() const {
xColor result;
withReadLock([&] {
result = { _textColor[RED_INDEX], _textColor[GREEN_INDEX], _textColor[BLUE_INDEX] };
});
return result;
}
void TextEntityItem::setTextColor(const rgbColor& value) {
withWriteLock([&] {
memcpy(_textColor, value, sizeof(_textColor));
});
}
void TextEntityItem::setTextColor(const xColor& value) {
withWriteLock([&] {
_textColor[RED_INDEX] = value.red;
_textColor[GREEN_INDEX] = value.green;
_textColor[BLUE_INDEX] = value.blue;
});
}
xColor TextEntityItem::getBackgroundColorX() const {
xColor result;
withReadLock([&] {
result = { _backgroundColor[RED_INDEX], _backgroundColor[GREEN_INDEX], _backgroundColor[BLUE_INDEX] };
});
return result;
}
void TextEntityItem::setBackgroundColor(const rgbColor& value) {
withWriteLock([&] {
memcpy(_backgroundColor, value, sizeof(_backgroundColor));
});
}
void TextEntityItem::setBackgroundColor(const xColor& value) {
withWriteLock([&] {
_backgroundColor[RED_INDEX] = value.red;
_backgroundColor[GREEN_INDEX] = value.green;
_backgroundColor[BLUE_INDEX] = value.blue;
});
}
bool TextEntityItem::getFaceCamera() const {
bool result;
withReadLock([&] {
result = _faceCamera;
});
return result;
}
void TextEntityItem::setFaceCamera(bool value) {
withWriteLock([&] {
_faceCamera = value;
});
}

View file

@ -53,40 +53,34 @@ public:
void** intersectedObject, bool precisionPicking) const override;
static const QString DEFAULT_TEXT;
void setText(const QString& value) { _text = value; }
const QString& getText() const { return _text; }
void setText(const QString& value);
QString getText() const;
static const float DEFAULT_LINE_HEIGHT;
void setLineHeight(float value) { _lineHeight = value; }
float getLineHeight() const { return _lineHeight; }
void setLineHeight(float value);
float getLineHeight() const;
static const xColor DEFAULT_TEXT_COLOR;
const rgbColor& getTextColor() const { return _textColor; }
xColor getTextColorX() const { xColor color = { _textColor[RED_INDEX], _textColor[GREEN_INDEX], _textColor[BLUE_INDEX] }; return color; }
// FIXME should not return a reference because of thread safety, but can't return an array
const rgbColor& getTextColor() const;
xColor getTextColorX() const;
void setTextColor(const rgbColor& value) { memcpy(_textColor, value, sizeof(_textColor)); }
void setTextColor(const xColor& value) {
_textColor[RED_INDEX] = value.red;
_textColor[GREEN_INDEX] = value.green;
_textColor[BLUE_INDEX] = value.blue;
}
void setTextColor(const rgbColor& value);
void setTextColor(const xColor& value);
static const xColor DEFAULT_BACKGROUND_COLOR;
const rgbColor& getBackgroundColor() const { return _backgroundColor; }
xColor getBackgroundColorX() const { xColor color = { _backgroundColor[RED_INDEX], _backgroundColor[GREEN_INDEX], _backgroundColor[BLUE_INDEX] }; return color; }
// FIXME should not return a reference because of thread safety, but can't return an array
const rgbColor& getBackgroundColor() const;
xColor getBackgroundColorX() const;
void setBackgroundColor(const rgbColor& value) { memcpy(_backgroundColor, value, sizeof(_backgroundColor)); }
void setBackgroundColor(const xColor& value) {
_backgroundColor[RED_INDEX] = value.red;
_backgroundColor[GREEN_INDEX] = value.green;
_backgroundColor[BLUE_INDEX] = value.blue;
}
void setBackgroundColor(const rgbColor& value);
void setBackgroundColor(const xColor& value);
static const bool DEFAULT_FACE_CAMERA;
bool getFaceCamera() const { return _faceCamera; }
void setFaceCamera(bool value) { _faceCamera = value; }
bool getFaceCamera() const;
void setFaceCamera(bool value);
protected:
private:
QString _text;
float _lineHeight;
rgbColor _textColor;

View file

@ -124,18 +124,26 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g
}
void WebEntityItem::setSourceUrl(const QString& value) {
if (_sourceUrl != value) {
auto newURL = QUrl::fromUserInput(value);
withWriteLock([&] {
if (_sourceUrl != value) {
auto newURL = QUrl::fromUserInput(value);
if (newURL.isValid()) {
_sourceUrl = newURL.toDisplayString();
} else {
qCDebug(entities) << "Clearing web entity source URL since" << value << "cannot be parsed to a valid URL.";
if (newURL.isValid()) {
_sourceUrl = newURL.toDisplayString();
} else {
qCDebug(entities) << "Clearing web entity source URL since" << value << "cannot be parsed to a valid URL.";
}
}
}
});
}
const QString& WebEntityItem::getSourceUrl() const { return _sourceUrl; }
QString WebEntityItem::getSourceUrl() const {
QString result;
withReadLock([&] {
result = _sourceUrl;
});
return result;
}
void WebEntityItem::setDPI(uint16_t value) {
_dpi = value;

View file

@ -52,7 +52,7 @@ public:
void** intersectedObject, bool precisionPicking) const override;
virtual void setSourceUrl(const QString& value);
const QString& getSourceUrl() const;
QString getSourceUrl() const;
virtual bool wantsHandControllerPointerEvents() const override { return true; }

View file

@ -208,10 +208,12 @@ ShapeType ZoneEntityItem::getShapeType() const {
}
void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
_compoundShapeURL = url;
if (_compoundShapeURL.isEmpty() && _shapeType == SHAPE_TYPE_COMPOUND) {
_shapeType = DEFAULT_SHAPE_TYPE;
}
withWriteLock([&] {
_compoundShapeURL = url;
if (_compoundShapeURL.isEmpty() && _shapeType == SHAPE_TYPE_COMPOUND) {
_shapeType = DEFAULT_SHAPE_TYPE;
}
});
}
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@ -223,7 +225,9 @@ bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
}
void ZoneEntityItem::setFilterURL(QString url) {
_filterURL = url;
withWriteLock([&] {
_filterURL = url;
});
if (DependencyManager::isSet<EntityEditFilters>()) {
auto entityEditFilters = DependencyManager::get<EntityEditFilters>();
qCDebug(entities) << "adding filter " << url << "for zone" << getEntityItemID();
@ -231,3 +235,22 @@ void ZoneEntityItem::setFilterURL(QString url) {
}
}
QString ZoneEntityItem::getFilterURL() const {
QString result;
withReadLock([&] {
result = _filterURL;
});
return result;
}
bool ZoneEntityItem::hasCompoundShapeURL() const {
return !getCompoundShapeURL().isEmpty();
}
QString ZoneEntityItem::getCompoundShapeURL() const {
QString result;
withReadLock([&] {
result = _compoundShapeURL;
});
return result;
}

View file

@ -58,8 +58,8 @@ public:
void setShapeType(ShapeType type) override { _shapeType = type; }
virtual ShapeType getShapeType() const override;
virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
const QString getCompoundShapeURL() const { return _compoundShapeURL; }
virtual bool hasCompoundShapeURL() const;
QString getCompoundShapeURL() const;
virtual void setCompoundShapeURL(const QString& url);
const KeyLightPropertyGroup& getKeyLightProperties() const { return _keyLightProperties; }
@ -74,7 +74,7 @@ public:
void setFlyingAllowed(bool value) { _flyingAllowed = value; }
bool getGhostingAllowed() const { return _ghostingAllowed; }
void setGhostingAllowed(bool value) { _ghostingAllowed = value; }
QString getFilterURL() const { return _filterURL; }
QString getFilterURL() const;
void setFilterURL(const QString url);
virtual bool supportsDetailedRayIntersection() const override { return true; }

View file

@ -376,10 +376,10 @@ public:
};
bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials,
const QHash<QString, QByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
const QHash<QString, QByteArray>& textureFilepaths, const QMultiMap<QString, QString>& _connectionChildMap) {
foreach (const QString& materialID, materials.keys()) {
foreach (const QString& childID, _connectionChildMap.values(materialID)) {
if (textureFilenames.contains(childID)) {
if (textureFilepaths.contains(childID)) {
return true;
}
}
@ -443,21 +443,48 @@ FBXLight extractLight(const FBXNode& object) {
return light;
}
QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
QString path = QFileInfo(url).path();
QByteArray filename = filepath;
QFileInfo checkFile(path + "/" + filepath);
QByteArray fixedTextureFilepath(QByteArray fbxRelativeFilepath, QUrl url) {
// first setup a QFileInfo for the passed relative filepath, with backslashes replaced by forward slashes
auto fileInfo = QFileInfo { fbxRelativeFilepath.replace("\\", "/") };
// check if the file exists at the RelativeFilename
if (!(checkFile.exists() && checkFile.isFile())) {
// if not, assume it is in the fbx directory
filename = filename.mid(filename.lastIndexOf('/') + 1);
#ifndef Q_OS_WIN
// it turns out that absolute windows paths starting with drive letters look like relative paths to QFileInfo on UNIX
// so we add a check for that here to work around it
bool isRelative = fbxRelativeFilepath[1] != ':' && fileInfo.isRelative();
#else
bool isRelative = fileInfo.isRelative();
#endif
if (isRelative) {
// the RelativeFilename pulled from the FBX is already correctly relative
// so simply return this as the filepath to use
return fbxRelativeFilepath;
} else {
// the RelativeFilename pulled from the FBX is an absolute path
// use the URL to figure out where the FBX is being loaded from
auto filename = fileInfo.fileName();
if (url.isLocalFile()) {
// the FBX is being loaded from the local filesystem
if (fileInfo.exists() && fileInfo.isFile()) {
// found a file at the absolute path in the FBX, return that path
return fbxRelativeFilepath;
} else {
// didn't find a file at the absolute path, assume it is right beside the FBX
// return just the filename as the relative path
return filename.toUtf8();
}
} else {
// this is a remote file, meaning we can't really do anything with the absolute path to the texture
// so assume it will be right beside the fbx
return filename.toUtf8();
}
}
return filename;
}
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QUrl& url) {
const FBXNode& node = _fbxNode;
QMap<QString, ExtractedMesh> meshes;
QHash<QString, QString> modelIDsToNames;
@ -833,11 +860,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
const int MODEL_UV_SCALING_MIN_SIZE = 2;
const int CROPPING_MIN_SIZE = 4;
if (subobject.name == "RelativeFilename" && subobject.properties.length() >= RELATIVE_FILENAME_MIN_SIZE) {
QByteArray filename = subobject.properties.at(0).toByteArray();
QByteArray filepath = filename.replace('\\', '/');
filename = fileOnUrl(filepath, url);
auto filepath = fixedTextureFilepath(subobject.properties.at(0).toByteArray(), url);
_textureFilepaths.insert(getID(object.properties), filepath);
_textureFilenames.insert(getID(object.properties), filename);
} else if (subobject.name == "TextureName" && subobject.properties.length() >= TEXTURE_NAME_MIN_SIZE) {
// trim the name from the timestamp
QString name = QString(subobject.properties.at(0).toByteArray());
@ -930,7 +955,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
QByteArray content;
foreach (const FBXNode& subobject, object.children) {
if (subobject.name == "RelativeFilename") {
filepath= subobject.properties.at(0).toByteArray();
filepath = subobject.properties.at(0).toByteArray();
filepath = filepath.replace('\\', '/');
} else if (subobject.name == "Content" && !subobject.properties.isEmpty()) {
@ -1502,7 +1527,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
geometry.materials = _fbxMaterials;
// see if any materials have texture children
bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap);
bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilepaths, _connectionChildMap);
for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
ExtractedMesh& extracted = it.value();
@ -1547,7 +1572,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
materialIndex++;
} else if (_textureFilenames.contains(childID)) {
} else if (_textureFilepaths.contains(childID)) {
FBXTexture texture = getTexture(childID);
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
int partTexture = extracted.partMaterialTextures.at(j).second;
@ -1818,13 +1843,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
return geometryPtr;
}
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) {
QBuffer buffer(const_cast<QByteArray*>(&model));
buffer.open(QIODevice::ReadOnly);
return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel);
}
FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) {
FBXReader reader;
reader._fbxNode = FBXReader::parseFBX(device);
reader._loadLightmaps = loadLightmaps;

View file

@ -268,7 +268,7 @@ class FBXGeometry {
public:
using Pointer = std::shared_ptr<FBXGeometry>;
QString originalURL;
QUrl originalURL;
QString author;
QString applicationName; ///< the name of the application that generated the model
@ -330,11 +330,11 @@ Q_DECLARE_METATYPE(FBXGeometry::Pointer)
/// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QUrl& url = QUrl(), bool loadLightmaps = true, float lightmapLevel = 1.0f);
/// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QUrl& url = QUrl(), bool loadLightmaps = true, float lightmapLevel = 1.0f);
class TextureParam {
public:
@ -402,19 +402,17 @@ public:
FBXNode _fbxNode;
static FBXNode parseFBX(QIODevice* device);
FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QString& url);
FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QUrl& url);
ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex);
QHash<QString, ExtractedMesh> meshes;
static void buildModelMesh(FBXMesh& extractedMesh, const QString& url);
static void buildModelMesh(FBXMesh& extractedMesh, const QUrl& url);
FBXTexture getTexture(const QString& textureID);
QHash<QString, QString> _textureNames;
// Hashes the original RelativeFilename of textures
QHash<QString, QByteArray> _textureFilepaths;
// Hashes the place to look for textures, in case they are not inlined
QHash<QString, QByteArray> _textureFilenames;
// Hashes texture content by filepath, in case they are inlined
QHash<QByteArray, QByteArray> _textureContent;
QHash<QString, TextureParam> _textureParams;

View file

@ -85,12 +85,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) {
FBXTexture texture;
const QByteArray& filepath = _textureFilepaths.value(textureID);
texture.content = _textureContent.value(filepath);
if (texture.content.isEmpty()) { // the content is not inlined
texture.filename = _textureFilenames.value(textureID);
} else { // use supplied filepath for inlined content
texture.filename = filepath;
}
texture.filename = filepath;
texture.name = _textureNames.value(textureID);
texture.transform.setIdentity();
@ -155,7 +150,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
if (_textureFilenames.contains(childTextureID)) {
if (_textureFilepaths.contains(childTextureID)) {
diffuseTexture = getTexture(diffuseTextureID);
}
}

View file

@ -388,7 +388,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn
return data.extracted;
}
void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QUrl& url) {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*");
unsigned int totalSourceIndices = 0;

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