mirror of
https://github.com/overte-org/overte.git
synced 2025-04-15 20:58:30 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into W-21204-tetherball-toy
This commit is contained in:
commit
5ce70decfc
157 changed files with 3810 additions and 1829 deletions
|
@ -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).
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
4
cmake/externals/openvr/CMakeLists.txt
vendored
4
cmake/externals/openvr/CMakeLists.txt
vendored
|
@ -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 ""
|
||||
|
|
|
@ -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" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
0
interface/resources/fonts/hifi-glyphs.ttf
Executable file → Normal 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]
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
22
interface/resources/qml/controls/WebEntityView.qml
Normal file
22
interface/resources/qml/controls/WebEntityView.qml
Normal 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";
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -243,12 +243,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
DropShadow {
|
||||
anchors.fill: actionIcon
|
||||
radius: 8.0
|
||||
color: "#80000000"
|
||||
source: actionIcon
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: messageArea;
|
||||
width: rectIcon.width;
|
||||
|
|
|
@ -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]});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@ Item {
|
|||
property var openMessage: null;
|
||||
property string subMenu: ""
|
||||
signal showDesktop();
|
||||
property bool shown: true
|
||||
|
||||
function setOption(value) {
|
||||
option = value;
|
||||
|
|
|
@ -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}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -138,7 +138,7 @@ private:
|
|||
int _rightEyeLookAtID;
|
||||
|
||||
// private methods
|
||||
void calculateMouthShapes();
|
||||
void calculateMouthShapes(float timeRatio);
|
||||
void applyEyelidOffset(glm::quat headOrientation);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
26
interface/src/networking/FileTypeProfile.cpp
Normal file
26
interface/src/networking/FileTypeProfile.cpp
Normal 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);
|
||||
}
|
25
interface/src/networking/FileTypeProfile.h
Normal file
25
interface/src/networking/FileTypeProfile.h
Normal 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
|
21
interface/src/networking/FileTypeRequestInterceptor.cpp
Normal file
21
interface/src/networking/FileTypeRequestInterceptor.cpp
Normal 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);
|
||||
}
|
26
interface/src/networking/FileTypeRequestInterceptor.h
Normal file
26
interface/src/networking/FileTypeRequestInterceptor.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
65
interface/src/networking/RequestFilters.cpp
Normal file
65
interface/src/networking/RequestFilters.cpp
Normal 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());
|
||||
}
|
||||
}
|
28
interface/src/networking/RequestFilters.h
Normal file
28
interface/src/networking/RequestFilters.h
Normal 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
|
|
@ -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() {
|
||||
|
|
|
@ -79,6 +79,7 @@ private:
|
|||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<TestingDialog> _testingDialog;
|
||||
QPointer<DomainConnectionDialog> _domainConnectionDialog;
|
||||
bool _closeAddressBar { false };
|
||||
};
|
||||
|
||||
#endif // hifi_DialogsManager_h
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -42,6 +42,8 @@ enum class Action {
|
|||
|
||||
LEFT_HAND = NUM_COMBINED_AXES,
|
||||
RIGHT_HAND,
|
||||
LEFT_FOOT,
|
||||
RIGHT_FOOT,
|
||||
|
||||
LEFT_HAND_CLICK,
|
||||
RIGHT_HAND_CLICK,
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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() { \
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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(); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {};
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue