Merge branch 'master' of github.com:highfidelity/hifi into discovery_appUi
|
@ -332,6 +332,10 @@ if (APPLE)
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
"${RESOURCES_DEV_DIR}/fonts"
|
||||
# add redirect json to macOS builds.
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
)
|
||||
|
||||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
|
@ -360,6 +364,9 @@ else()
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
|
|
5
interface/resources/images/eyeClosed.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="31" height="23" viewBox="0 0 31 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.59534 11.0156C6.16042 13.4128 9.65987 15.5898 13.6042 16.1774C17.686 16.7856 22.4164 15.7196 27.3057 11.0659C22.0721 6.07309 17.0642 5.14115 12.9153 5.90073C8.99427 6.61859 5.69298 8.87688 3.59534 11.0156ZM12.455 3.27591C17.7727 2.30235 23.9836 3.74895 30.1053 10.1333L31 11.0664L30.1053 11.9994C24.3636 17.9875 18.4774 19.5983 13.2276 18.8161C8.06048 18.0463 3.70384 14.9892 0.837069 11.9994L0 11.1265L0.778477 10.1986C3.05338 7.48717 7.2318 4.23217 12.455 3.27591Z" fill="#3D3D3D"/>
|
||||
<ellipse cx="15.6539" cy="10.9218" rx="3.65386" ry="3.81061" fill="#3D3D3D"/>
|
||||
<line x1="25" y1="2.12132" x2="7.12132" y2="20" stroke="#3D3D3D" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 825 B |
4
interface/resources/images/eyeOpen.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="31" height="16" viewBox="0 0 31 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.59534 8.01564C6.16042 10.4128 9.65987 12.5898 13.6042 13.1774C17.686 13.7856 22.4164 12.7196 27.3057 8.06585C22.0721 3.07309 17.0642 2.14115 12.9153 2.90073C8.99427 3.61859 5.69298 5.87688 3.59534 8.01564ZM12.455 0.275915C17.7727 -0.697651 23.9836 0.748949 30.1053 7.13329L31 8.06636L30.1053 8.99944C24.3636 14.9875 18.4774 16.5983 13.2276 15.8161C8.06048 15.0463 3.70384 11.9892 0.837069 8.99944L0 8.12646L0.778477 7.1986C3.05338 4.48717 7.2318 1.23217 12.455 0.275915Z" fill="#3D3D3D"/>
|
||||
<ellipse cx="15.644" cy="7.92179" rx="3.65386" ry="3.81061" fill="#3D3D3D"/>
|
||||
</svg>
|
After Width: | Height: | Size: 721 B |
BIN
interface/resources/images/loadingBar_placard.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
interface/resources/images/loadingBar_progress.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_auth.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_auth.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_vague.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_vague.png
Normal file
After Width: | Height: | Size: 5 KiB |
|
@ -23,6 +23,7 @@ ModalWindow {
|
|||
objectName: "LoginDialog"
|
||||
implicitWidth: 520
|
||||
implicitHeight: 320
|
||||
closeButtonVisible: true
|
||||
destroyOnCloseButton: true
|
||||
destroyOnHidden: true
|
||||
visible: true
|
||||
|
|
|
@ -117,27 +117,27 @@ Item {
|
|||
}
|
||||
spacing: hifi.dimensions.contentSpacing.y / 2
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
placeholderText: qsTr("Username or Email")
|
||||
TextField {
|
||||
id: usernameField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
placeholderText: qsTr("Username or Email")
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
|
||||
placeholderText: qsTr("Password")
|
||||
echoMode: TextInput.Password
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
TextField {
|
||||
id: passwordField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
|
||||
placeholderText: qsTr("Password")
|
||||
echoMode: TextInput.Password
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
}
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
|
@ -176,7 +176,7 @@ Item {
|
|||
anchors {
|
||||
left: parent.left
|
||||
top: form.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
}
|
||||
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
@ -201,7 +201,7 @@ Item {
|
|||
anchors {
|
||||
right: parent.right
|
||||
top: form.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
|
|
@ -15,7 +15,6 @@ import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
|||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: linkAccountBody
|
||||
clip: true
|
||||
|
@ -87,6 +86,23 @@ Item {
|
|||
height: 48
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: flavorText
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("Sign in to High Fidelity to make friends, get HFC, and buy interesting things on the Marketplace!")
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
|
@ -97,7 +113,6 @@ Item {
|
|||
}
|
||||
|
||||
visible: false
|
||||
|
||||
text: qsTr("Username or password incorrect.")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
|
@ -117,22 +132,21 @@ Item {
|
|||
}
|
||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
text: Settings.getValue("wallet/savedUsername", "");
|
||||
width: parent.width
|
||||
focus: true
|
||||
label: "Username or Email"
|
||||
placeholderText: "Username or Email"
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
z: 10
|
||||
y: usernameField.height
|
||||
anchors {
|
||||
left: usernameField.left
|
||||
top: usernameField.top
|
||||
leftMargin: usernameField.textFieldLabel.contentWidth + 10
|
||||
topMargin: -19
|
||||
right: usernameField.right
|
||||
top: usernameField.bottom
|
||||
topMargin: 4
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||
|
@ -143,26 +157,32 @@ Item {
|
|||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
Component.onCompleted: {
|
||||
var savedUsername = Settings.getValue("wallet/savedUsername", "");
|
||||
usernameField.text = savedUsername === "Unknown user" ? "" : savedUsername;
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
width: parent.width
|
||||
|
||||
label: "Password"
|
||||
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
|
||||
placeholderText: "Password"
|
||||
activeFocusOnPress: true
|
||||
echoMode: TextInput.Password
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
ShortcutText {
|
||||
id: forgotPasswordShortcut
|
||||
y: passwordField.height
|
||||
z: 10
|
||||
anchors {
|
||||
left: passwordField.left
|
||||
top: passwordField.top
|
||||
leftMargin: passwordField.textFieldLabel.contentWidth + 10
|
||||
topMargin: -19
|
||||
right: passwordField.right
|
||||
top: passwordField.bottom
|
||||
topMargin: 4
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||
|
@ -179,12 +199,45 @@ Item {
|
|||
root.isPassword = true;
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
}
|
||||
Rectangle {
|
||||
id: showPasswordHitbox
|
||||
z: 10
|
||||
x: passwordField.width - ((passwordField.height) * 31 / 23)
|
||||
width: parent.width - (parent.width - (parent.height * 31/16))
|
||||
height: parent.height
|
||||
anchors {
|
||||
right: parent.right
|
||||
}
|
||||
color: "transparent"
|
||||
|
||||
CheckBox {
|
||||
id: showPassword
|
||||
text: "Show password"
|
||||
Image {
|
||||
id: showPasswordImage
|
||||
y: (passwordField.height - (passwordField.height * 16 / 23)) / 2
|
||||
width: passwordField.width - (passwordField.width - (((passwordField.height) * 31/23)))
|
||||
height: passwordField.height * 16 / 23
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 3
|
||||
}
|
||||
source: "../../images/eyeOpen.svg"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: passwordFieldMouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
property bool showPassword: false
|
||||
onClicked: {
|
||||
showPassword = !showPassword;
|
||||
passwordField.echoMode = showPassword ? TextInput.Normal : TextInput.Password;
|
||||
showPasswordImage.source = showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg";
|
||||
showPasswordImage.height = showPassword ? passwordField.height : passwordField.height * 16 / 23;
|
||||
showPasswordImage.y = showPassword ? 0 : (passwordField.height - showPasswordImage.height) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
|
@ -206,6 +259,26 @@ Item {
|
|||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
CheckBox {
|
||||
id: autoLogoutCheckbox
|
||||
checked: !Settings.getValue("wallet/autoLogout", true)
|
||||
text: "Keep me signed in"
|
||||
boxSize: 20;
|
||||
labelFontSize: 15
|
||||
color: hifi.colors.black
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("wallet/autoLogout", !checked);
|
||||
if (checked) {
|
||||
Settings.setValue("wallet/savedUsername", Account.username);
|
||||
} else {
|
||||
Settings.setValue("wallet/savedUsername", "");
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
Settings.setValue("wallet/autoLogout", !checked);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: linkAccountButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
@ -216,12 +289,6 @@ Item {
|
|||
|
||||
onClicked: linkAccountBody.login()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.tryDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -234,7 +301,7 @@ Item {
|
|||
RalewaySemiBold {
|
||||
size: hifi.fontSizes.inputLabel
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Don't have an account?")
|
||||
text: qsTr("New to High Fidelity?")
|
||||
}
|
||||
|
||||
Button {
|
||||
|
@ -287,11 +354,23 @@ Item {
|
|||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
if (Settings.getValue("loginDialogPoppedUp", false)) {
|
||||
var data = {
|
||||
"action": "user logged in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
mainTextContainer.visible = true
|
||||
toggleLoading(false)
|
||||
if (Settings.getValue("loginDialogPoppedUp", false)) {
|
||||
var data = {
|
||||
"action": "user failed logging in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
onHandleLinkCompleted: {
|
||||
console.log("Link Succeeded")
|
||||
|
|
|
@ -175,7 +175,14 @@ Rectangle {
|
|||
displayNameInput.text = getAvatarsData.displayName;
|
||||
currentAvatarSettings = getAvatarsData.currentAvatarSettings;
|
||||
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
var bookmarkAvatarIndex = allAvatars.findAvatarIndexByValue(currentAvatar);
|
||||
if (bookmarkAvatarIndex === -1) {
|
||||
currentAvatar.name = '';
|
||||
} else {
|
||||
currentAvatar.name = allAvatars.get(bookmarkAvatarIndex).name;
|
||||
allAvatars.move(bookmarkAvatarIndex, 0, 1);
|
||||
}
|
||||
view.setPage(0);
|
||||
} else if (message.method === 'updateAvatarInBookmarks') {
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if (message.method === 'selectAvatarEntity') {
|
||||
|
|
|
@ -79,7 +79,7 @@ StackView {
|
|||
return;
|
||||
}
|
||||
location.text = targetString;
|
||||
toggleOrGo(true, targetString);
|
||||
toggleOrGo(targetString, true);
|
||||
clearAddressLineTimer.start();
|
||||
}
|
||||
|
||||
|
@ -399,7 +399,7 @@ StackView {
|
|||
}
|
||||
}
|
||||
|
||||
function toggleOrGo(fromSuggestions, address) {
|
||||
function toggleOrGo(address, fromSuggestions) {
|
||||
if (address !== undefined && address !== "") {
|
||||
addressBarDialog.loadAddress(address, fromSuggestions);
|
||||
clearAddressLineTimer.start();
|
||||
|
|
|
@ -94,5 +94,25 @@ Frame {
|
|||
color: hifi.colors.lightGray
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GlyphButton {
|
||||
id: closeButton
|
||||
visible: window.closeButtonVisible
|
||||
width: 30
|
||||
y: -hifi.dimensions.modalDialogTitleHeight
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
topMargin: 10
|
||||
rightMargin: 10
|
||||
}
|
||||
glyph: hifi.glyphs.close
|
||||
size: 23
|
||||
onClicked: {
|
||||
window.clickedCloseButton = true;
|
||||
window.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ ScrollingWindow {
|
|||
destroyOnHidden: true
|
||||
frame: ModalFrame { }
|
||||
|
||||
property bool closeButtonVisible: false
|
||||
// only applicable for if close button is visible.
|
||||
property bool clickedCloseButton: false
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
property bool draggable: false
|
||||
|
||||
|
|
934
interface/resources/serverless/redirect.json
Normal file
|
@ -0,0 +1,934 @@
|
|||
{
|
||||
"DataVersion": 0,
|
||||
"Paths":
|
||||
{
|
||||
"/": "/4,1.4,4/0,0.49544,0,0.868645"
|
||||
},
|
||||
"Entities": [
|
||||
{
|
||||
"clientOnly": false,
|
||||
"collidesWith": "static,dynamic,kinematic,otherAvatar,",
|
||||
"collisionMask": 23,
|
||||
"created": "2018-09-05T18:13:00Z",
|
||||
"dimensions": {
|
||||
"blue": 1.159199833869934,
|
||||
"green": 2.8062009811401367,
|
||||
"red": 1.6216505765914917,
|
||||
"x": 1.6216505765914917,
|
||||
"y": 2.8062009811401367,
|
||||
"z": 1.159199833869934
|
||||
},
|
||||
"id": "{d0ed60b8-9174-4c56-8e78-2c5399329ae0}",
|
||||
"lastEdited": 1536171372916208,
|
||||
"lastEditedBy": "{151cb20e-715a-4c80-aa0d-5b58b1c8a0c9}",
|
||||
"locked": true,
|
||||
"name": "Try Again Zone",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue":4.015342712402344,
|
||||
"green":1.649999976158142,
|
||||
"red":2.00921893119812,
|
||||
"x":2.00921893119812,
|
||||
"y":1.649999976158142,
|
||||
"z":4.015342712402344
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 3.4421300888061523,
|
||||
"x": 1.6001315116882324,
|
||||
"y": -0.07100248336791992,
|
||||
"z": 0.14220571517944336
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9914448857307434,
|
||||
"x": 0,
|
||||
"y": -0.13052619993686676,
|
||||
"z": 0
|
||||
},
|
||||
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/zoneTryAgainEntityScript.js",
|
||||
"shapeType": "box",
|
||||
"type": "Zone",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 8.645400047302246,
|
||||
"green": 0.20000000298023224,
|
||||
"red": 20.025121688842773,
|
||||
"x": 20.025121688842773,
|
||||
"y": 0.20000000298023224,
|
||||
"z": 8.645400047302246
|
||||
},
|
||||
"id": "{e44fb546-b34a-4966-9b11-73556f800d21}",
|
||||
"lastEdited": 1536107948776951,
|
||||
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||
"locked": true,
|
||||
"name": "ceiling",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 4.846520900726318,
|
||||
"green": 2.912982940673828,
|
||||
"red": 5.739595890045166,
|
||||
"x": 5.739595890045166,
|
||||
"y": 2.912982940673828,
|
||||
"z": 4.846520900726318
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 21.812576293945312,
|
||||
"x": -5.16669225692749,
|
||||
"y": -7.993305206298828,
|
||||
"z": -6.059767246246338
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.970295786857605,
|
||||
"x": 0,
|
||||
"y": -0.24192190170288086,
|
||||
"z": 0
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 6.9401350021362305,
|
||||
"green": 0.04553089290857315,
|
||||
"red": 7.004304885864258,
|
||||
"x": 7.004304885864258,
|
||||
"y": 0.04553089290857315,
|
||||
"z": 6.9401350021362305
|
||||
},
|
||||
"id": "{8cd93fe5-16c0-44b7-b1e9-e7e06c4e9228}",
|
||||
"lastEdited": 1536107948774796,
|
||||
"lastEditedBy": "{4eecd88f-ef9b-4a83-bb9a-7f7496209c6b}",
|
||||
"locked": true,
|
||||
"name": "floor",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 3.6175529956817627,
|
||||
"green": 0,
|
||||
"red": 4.102385997772217,
|
||||
"x": 4.102385997772217,
|
||||
"y": 0,
|
||||
"z": 3.6175529956817627
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 9.860417366027832,
|
||||
"x": -0.8278226852416992,
|
||||
"y": -4.930208683013916,
|
||||
"z": -1.3126556873321533
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8660253882408142,
|
||||
"x": -1.5922749298624694e-05,
|
||||
"y": 0.5,
|
||||
"z": -4.572480611386709e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{147272dc-a344-4171-9621-efc1c2095997}",
|
||||
"lastEdited": 1536107948776823,
|
||||
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||
"locked": true,
|
||||
"name": "leftWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 6.1806135177612305,
|
||||
"green": 1.0066027641296387,
|
||||
"red": 1.4690406322479248,
|
||||
"x": 1.4690406322479248,
|
||||
"y": 1.0066027641296387,
|
||||
"z": 6.1806135177612305
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -4.371703147888184,
|
||||
"y": -4.834141254425049,
|
||||
"z": 0.33986949920654297
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8637980222702026,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": 0.5038070678710938,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{5f2b89b8-47e3-4915-a966-d46307a40f06}",
|
||||
"lastEdited": 1536107948774605,
|
||||
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||
"locked": true,
|
||||
"name": "backWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 5.268576622009277,
|
||||
"green": 1.0066027641296387,
|
||||
"red": 6.093774318695068,
|
||||
"x": 6.093774318695068,
|
||||
"y": 1.0066027641296387,
|
||||
"z": 5.268576622009277
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": 0.25303030014038086,
|
||||
"y": -4.834141254425049,
|
||||
"z": -0.5721673965454102
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9662165641784668,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": -0.2576791048049927,
|
||||
"z": 1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 14.40000057220459,
|
||||
"green": 14.40000057220459,
|
||||
"red": 14.40000057220459,
|
||||
"x": 14.40000057220459,
|
||||
"y": 14.40000057220459,
|
||||
"z": 14.40000057220459
|
||||
},
|
||||
"id": "{baf96345-8f68-4068-af4c-3c690035852a}",
|
||||
"lastEdited": 1536107948775591,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"locked": true,
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 2.3440732955932617,
|
||||
"green": 1.6162219047546387,
|
||||
"red": 1.8748211860656738,
|
||||
"x": 1.8748211860656738,
|
||||
"y": 1.6162219047546387,
|
||||
"z": 2.3440732955932617
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 24.9415340423584,
|
||||
"x": -10.595945358276367,
|
||||
"y": -10.854545593261719,
|
||||
"z": -10.126693725585938
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8697794675827026,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.4933699369430542,
|
||||
"z": -4.57763671875e-05
|
||||
},
|
||||
"shapeType": "box",
|
||||
"skyboxMode": "enabled",
|
||||
"type": "Zone",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"alpha": 0,
|
||||
"alphaFinish": 0,
|
||||
"alphaStart": 1,
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 211,
|
||||
"green": 227,
|
||||
"red": 104
|
||||
},
|
||||
"colorFinish": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"blue": 211,
|
||||
"green": 227,
|
||||
"red": 104,
|
||||
"x": 104,
|
||||
"y": 227,
|
||||
"z": 211
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 2.5,
|
||||
"green": 2.5,
|
||||
"red": 2.5,
|
||||
"x": 2.5,
|
||||
"y": 2.5,
|
||||
"z": 2.5
|
||||
},
|
||||
"emitAcceleration": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"emitDimensions": {
|
||||
"blue": 1,
|
||||
"green": 1,
|
||||
"red": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"emitOrientation": {
|
||||
"w": 0.9993909597396851,
|
||||
"x": 0.034897372126579285,
|
||||
"y": -1.525880907138344e-05,
|
||||
"z": -1.525880907138344e-05
|
||||
},
|
||||
"emitRate": 2,
|
||||
"emitSpeed": 0,
|
||||
"id": "{639a51f0-8613-4e46-bc7e-fef24597df73}",
|
||||
"lastEdited": 1536107948776693,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"lifespan": 10,
|
||||
"locked": true,
|
||||
"maxParticles": 40,
|
||||
"name": "Rays",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"particleRadius": 0.75,
|
||||
"polarFinish": 3.1415927410125732,
|
||||
"position": {
|
||||
"blue": 1.3553659915924072,
|
||||
"green": 1.2890124320983887,
|
||||
"red": 2.5663273334503174,
|
||||
"x": 2.5663273334503174,
|
||||
"y": 1.2890124320983887,
|
||||
"z": 1.3553659915924072
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 4.330127239227295,
|
||||
"x": 0.4012637138366699,
|
||||
"y": -0.8760511875152588,
|
||||
"z": -0.8096976280212402
|
||||
},
|
||||
"radiusFinish": 0.10000000149011612,
|
||||
"radiusStart": 0,
|
||||
"rotation": {
|
||||
"w": 0.9803768396377563,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.19707024097442627,
|
||||
"z": -7.62939453125e-05
|
||||
},
|
||||
"speedSpread": 0,
|
||||
"spinFinish": null,
|
||||
"spinStart": null,
|
||||
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/stripe.png",
|
||||
"type": "ParticleEffect",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"alpha": 0,
|
||||
"alphaFinish": 0,
|
||||
"alphaStart": 1,
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 255,
|
||||
"green": 205,
|
||||
"red": 3
|
||||
},
|
||||
"colorFinish": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"blue": 255,
|
||||
"green": 204,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 204,
|
||||
"z": 255
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 2.5,
|
||||
"green": 2.5,
|
||||
"red": 2.5,
|
||||
"x": 2.5,
|
||||
"y": 2.5,
|
||||
"z": 2.5
|
||||
},
|
||||
"emitAcceleration": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"emitDimensions": {
|
||||
"blue": 1,
|
||||
"green": 1,
|
||||
"red": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"emitOrientation": {
|
||||
"w": 0.9993909597396851,
|
||||
"x": 0.034897372126579285,
|
||||
"y": -1.525880907138344e-05,
|
||||
"z": -1.525880907138344e-05
|
||||
},
|
||||
"emitRate": 2,
|
||||
"emitSpeed": 0,
|
||||
"emitterShouldTrail": true,
|
||||
"id": "{e62ced49-fa18-4ae1-977f-abef5bc0f3ba}",
|
||||
"lastEdited": 1536107948775366,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"lifespan": 10,
|
||||
"locked": true,
|
||||
"maxParticles": 40,
|
||||
"name": "Rays",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"particleRadius": 0.75,
|
||||
"polarFinish": 3.1415927410125732,
|
||||
"position": {
|
||||
"blue": 3.814434051513672,
|
||||
"green": 1.2890124320983887,
|
||||
"red": 1.2254328727722168,
|
||||
"x": 1.2254328727722168,
|
||||
"y": 1.2890124320983887,
|
||||
"z": 3.814434051513672
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 4.330127239227295,
|
||||
"x": -0.9396307468414307,
|
||||
"y": -0.8760511875152588,
|
||||
"z": 1.6493704319000244
|
||||
},
|
||||
"radiusFinish": 0.10000000149011612,
|
||||
"radiusStart": 0,
|
||||
"rotation": {
|
||||
"w": 0.9594720602035522,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.28178834915161133,
|
||||
"z": -4.57763671875e-05
|
||||
},
|
||||
"speedSpread": 0,
|
||||
"spinFinish": null,
|
||||
"spinStart": null,
|
||||
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/stripe.png",
|
||||
"type": "ParticleEffect",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"alpha": 0,
|
||||
"alphaFinish": 0,
|
||||
"alphaStart": 0.25,
|
||||
"clientOnly": false,
|
||||
"colorFinish": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"blue": 255,
|
||||
"green": 255,
|
||||
"red": 255,
|
||||
"x": 255,
|
||||
"y": 255,
|
||||
"z": 255
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 13.24000072479248,
|
||||
"green": 13.24000072479248,
|
||||
"red": 13.24000072479248,
|
||||
"x": 13.24000072479248,
|
||||
"y": 13.24000072479248,
|
||||
"z": 13.24000072479248
|
||||
},
|
||||
"emitAcceleration": {
|
||||
"blue": 0,
|
||||
"green": 0.10000000149011612,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0.10000000149011612,
|
||||
"z": 0
|
||||
},
|
||||
"emitDimensions": {
|
||||
"blue": 1,
|
||||
"green": 1,
|
||||
"red": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"emitOrientation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"emitRate": 6,
|
||||
"emitSpeed": 0,
|
||||
"id": "{298c0571-cbd8-487b-8640-64037d6a8414}",
|
||||
"lastEdited": 1536107948776382,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"lifespan": 10,
|
||||
"locked": true,
|
||||
"maxParticles": 10,
|
||||
"name": "Stars",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"particleRadius": 0.07000000029802322,
|
||||
"polarFinish": 3.1415927410125732,
|
||||
"position": {
|
||||
"blue": 1.3712034225463867,
|
||||
"green": 0.3698839843273163,
|
||||
"red": 2.6216418743133545,
|
||||
"x": 2.6216418743133545,
|
||||
"y": 0.3698839843273163,
|
||||
"z": 1.3712034225463867
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 22.932353973388672,
|
||||
"x": -8.844534873962402,
|
||||
"y": -11.096293449401855,
|
||||
"z": -10.09497356414795
|
||||
},
|
||||
"radiusFinish": 0,
|
||||
"radiusStart": 0,
|
||||
"rotation": {
|
||||
"w": 0.9852597713470459,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -0.17106890678405762,
|
||||
"z": -7.62939453125e-05
|
||||
},
|
||||
"speedSpread": 0,
|
||||
"spinFinish": null,
|
||||
"spinStart": null,
|
||||
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/star.png",
|
||||
"type": "ParticleEffect",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 2.1097896099090576,
|
||||
"green": 0.04847164824604988,
|
||||
"red": 1.458284616470337,
|
||||
"x": 1.458284616470337,
|
||||
"y": 0.04847164824604988,
|
||||
"z": 2.1097896099090576
|
||||
},
|
||||
"id": "{6625dbb8-ff25-458d-a92e-644b58460604}",
|
||||
"lastEdited": 1536107948776195,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"locked": true,
|
||||
"modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal1.fbx",
|
||||
"name": "Try Again",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 3.946338653564453,
|
||||
"green": 0.09449335932731628,
|
||||
"red": 1.594836711883545,
|
||||
"x": 1.594836711883545,
|
||||
"y": 0.09449335932731628,
|
||||
"z": 3.946338653564453
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.5651814937591553,
|
||||
"x": 0.3122459650039673,
|
||||
"y": -1.188097357749939,
|
||||
"z": 2.663747787475586
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8220492601394653,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.5693598985671997,
|
||||
"z": -0.0001068115234375
|
||||
},
|
||||
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/tryAgainEntityScript.js",
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 0.06014331430196762,
|
||||
"green": 2.582186460494995,
|
||||
"red": 2.582186698913574,
|
||||
"x": 2.582186698913574,
|
||||
"y": 2.582186460494995,
|
||||
"z": 0.06014331430196762
|
||||
},
|
||||
"id": "{dfe92dce-f09d-4e9e-b3ed-c68ecd4d476f}",
|
||||
"lastEdited": 1536108160862286,
|
||||
"lastEditedBy": "{4656d4a8-5e61-4230-ab34-2888d7945bd6}",
|
||||
"modelURL": "",
|
||||
"name": "Oops Dialog",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 1.45927095413208,
|
||||
"green": 1.6763916015625,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 1.6763916015625,
|
||||
"z": 1.45927095413208
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 3.6522583961486816,
|
||||
"x": -1.8261291980743408,
|
||||
"y": -0.14973759651184082,
|
||||
"z": -0.36685824394226074
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8684672117233276,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": 0.4957197904586792,
|
||||
"z": -7.62939453125e-05
|
||||
},
|
||||
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/oopsEntityScript.js",
|
||||
"scriptTimestamp": 1536102551825,
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{144a8cf4-b0e8-489a-9403-d74d4dc4cb3e}",
|
||||
"lastEdited": 1536107948775774,
|
||||
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||
"locked": true,
|
||||
"name": "rightWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 0,
|
||||
"green": 1.0061144828796387,
|
||||
"red": 4.965089321136475,
|
||||
"x": 4.965089321136475,
|
||||
"y": 1.0061144828796387,
|
||||
"z": 0
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -0.8756546974182129,
|
||||
"y": -4.834629535675049,
|
||||
"z": -5.8407440185546875
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8637980222702026,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": 0.5038070678710938,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"collidesWith": "static,dynamic,kinematic,otherAvatar,",
|
||||
"collisionMask": 23,
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 1.159199833869934,
|
||||
"green": 2.8062009811401367,
|
||||
"red": 1.6216505765914917,
|
||||
"x": 1.6216505765914917,
|
||||
"y": 2.8062009811401367,
|
||||
"z": 1.159199833869934
|
||||
},
|
||||
"id": "{37f53408-3d0c-42a5-9891-e6c40a227349}",
|
||||
"lastEdited": 1536107948775010,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"locked": true,
|
||||
"name": "Back Zone",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 1.8632707595825195,
|
||||
"green": 1.6500625610351562,
|
||||
"red": 3.3211965560913086,
|
||||
"x": 3.3211965560913086,
|
||||
"y": 1.6500625610351562,
|
||||
"z": 1.8632707595825195
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 3.4421300888061523,
|
||||
"x": 1.6001315116882324,
|
||||
"y": -0.07100248336791992,
|
||||
"z": 0.14220571517944336
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9304176568984985,
|
||||
"x": 0,
|
||||
"y": -0.36650121212005615,
|
||||
"z": 0
|
||||
},
|
||||
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/zoneBackEntityScript.js",
|
||||
"shapeType": "box",
|
||||
"type": "Zone",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{aa6e680c-6750-4776-95bc-ef3118cace5c}",
|
||||
"lastEdited": 1536107948775945,
|
||||
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||
"locked": true,
|
||||
"name": "frontWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 2.662257671356201,
|
||||
"green": 1.0063786506652832,
|
||||
"red": 1.4868733882904053,
|
||||
"x": 1.4868733882904053,
|
||||
"y": 1.0063786506652832,
|
||||
"z": 2.662257671356201
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -4.353870391845703,
|
||||
"y": -4.834365367889404,
|
||||
"z": -3.1784863471984863
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9666743278503418,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": -0.2560006380081177,
|
||||
"z": 1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 2.1097896099090576,
|
||||
"green": 0.04847164824604988,
|
||||
"red": 1.458284616470337,
|
||||
"x": 1.458284616470337,
|
||||
"y": 0.04847164824604988,
|
||||
"z": 2.1097896099090576
|
||||
},
|
||||
"id": "{303631f1-04f3-42a6-b8a8-8dd4b65d1231}",
|
||||
"lastEdited": 1536107948776513,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"locked": true,
|
||||
"modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal2.fbx",
|
||||
"name": "Back",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 1.5835940837860107,
|
||||
"green": 0.09449335932731628,
|
||||
"red": 3.028078079223633,
|
||||
"x": 3.028078079223633,
|
||||
"y": 0.09449335932731628,
|
||||
"z": 1.5835940837860107
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.5651814937591553,
|
||||
"x": 1.7454873323440552,
|
||||
"y": -1.188097357749939,
|
||||
"z": 0.3010033369064331
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9084458351135254,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.4179598093032837,
|
||||
"z": -0.0001068115234375
|
||||
},
|
||||
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/backEntityScript.js",
|
||||
"scriptTimestamp": 1535751754379,
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"alpha": 0,
|
||||
"alphaFinish": 0,
|
||||
"alphaStart": 0.25,
|
||||
"clientOnly": false,
|
||||
"colorFinish": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"blue": 255,
|
||||
"green": 255,
|
||||
"red": 255,
|
||||
"x": 255,
|
||||
"y": 255,
|
||||
"z": 255
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 13.24000072479248,
|
||||
"green": 13.24000072479248,
|
||||
"red": 13.24000072479248,
|
||||
"x": 13.24000072479248,
|
||||
"y": 13.24000072479248,
|
||||
"z": 13.24000072479248
|
||||
},
|
||||
"emitAcceleration": {
|
||||
"blue": 0,
|
||||
"green": 0.10000000149011612,
|
||||
"red": 0,
|
||||
"x": 0,
|
||||
"y": 0.10000000149011612,
|
||||
"z": 0
|
||||
},
|
||||
"emitDimensions": {
|
||||
"blue": 1,
|
||||
"green": 1,
|
||||
"red": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"emitOrientation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"emitRate": 6,
|
||||
"emitSpeed": 0,
|
||||
"emitterShouldTrail": true,
|
||||
"id": "{8ded39e6-303c-48f2-be79-81b715cca9f7}",
|
||||
"lastEdited": 1536107948777127,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"lifespan": 10,
|
||||
"locked": true,
|
||||
"maxParticles": 10,
|
||||
"name": "Stars",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"particleRadius": 0.07000000029802322,
|
||||
"polarFinish": 3.1415927410125732,
|
||||
"position": {
|
||||
"blue": 3.78922963142395,
|
||||
"green": 0.3698839843273163,
|
||||
"red": 1.1863799095153809,
|
||||
"x": 1.1863799095153809,
|
||||
"y": 0.3698839843273163,
|
||||
"z": 3.78922963142395
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 22.932353973388672,
|
||||
"x": -10.279796600341797,
|
||||
"y": -11.096293449401855,
|
||||
"z": -7.676947593688965
|
||||
},
|
||||
"radiusFinish": 0,
|
||||
"radiusStart": 0,
|
||||
"rotation": {
|
||||
"w": 0.996429443359375,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -0.08442819118499756,
|
||||
"z": -4.57763671875e-05
|
||||
},
|
||||
"speedSpread": 0,
|
||||
"spinFinish": null,
|
||||
"spinStart": null,
|
||||
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/star.png",
|
||||
"type": "ParticleEffect",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
}
|
||||
],
|
||||
"Id": "{18abccad-2d57-4176-9d89-24dc424916f5}",
|
||||
"Version": 93
|
||||
}
|
|
@ -1186,13 +1186,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||
|
||||
connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl)));
|
||||
connect(&domainHandler, SIGNAL(redirectToErrorDomainURL(QUrl)), SLOT(goToErrorDomainURL(QUrl)));
|
||||
connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){
|
||||
setCrashAnnotation("domain", domainURL.toString().toStdString());
|
||||
});
|
||||
connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
|
||||
connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle()));
|
||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &Application::clearDomainAvatars);
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() {
|
||||
getOverlays().deleteOverlay(getTabletScreenID());
|
||||
getOverlays().deleteOverlay(getTabletHomeButtonID());
|
||||
|
@ -1200,6 +1200,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
});
|
||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused);
|
||||
|
||||
nodeList->getDomainHandler().setErrorDomainURL(QUrl(REDIRECT_HIFI_ADDRESS));
|
||||
|
||||
// We could clear ATP assets only when changing domains, but it's possible that the domain you are connected
|
||||
// to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid.
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get<ScriptCache>().data(), &ScriptCache::clearATPScriptsFromCache);
|
||||
|
@ -1641,7 +1643,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
audioClient->setMuted(!audioClient->isMuted());
|
||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||
cycleCamera();
|
||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU) && !isInterstitialMode()) {
|
||||
toggleTabletUI();
|
||||
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
||||
auto oldPos = getApplicationCompositor().getReticlePosition();
|
||||
|
@ -2250,6 +2252,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
|
||||
connect(&domainHandler, &DomainHandler::domainURLChanged, this, &Application::addAssetToWorldMessageClose);
|
||||
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &Application::addAssetToWorldMessageClose);
|
||||
|
||||
updateSystemTabletMode();
|
||||
|
||||
|
@ -2300,6 +2303,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
|
||||
AndroidHelper::instance().notifyLoadComplete();
|
||||
#endif
|
||||
|
||||
static int CHECK_LOGIN_TIMER = 3000;
|
||||
QTimer* checkLoginTimer = new QTimer(this);
|
||||
checkLoginTimer->setInterval(CHECK_LOGIN_TIMER);
|
||||
checkLoginTimer->setSingleShot(true);
|
||||
connect(checkLoginTimer, &QTimer::timeout, this, [this]() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
if (!accountManager->isLoggedIn()) {
|
||||
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(true);
|
||||
dialogsManager->showLoginDialog();
|
||||
QJsonObject loginData = {};
|
||||
loginData["action"] = "login dialog shown";
|
||||
UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData);
|
||||
}
|
||||
});
|
||||
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(false);
|
||||
checkLoginTimer->start();
|
||||
}
|
||||
|
||||
void Application::updateVerboseLogging() {
|
||||
|
@ -2433,6 +2454,8 @@ void Application::onAboutToQuit() {
|
|||
// so its persisted explicitly here
|
||||
Setting::Handle<QString>{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName());
|
||||
|
||||
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(false);
|
||||
|
||||
getActiveDisplayPlugin()->deactivate();
|
||||
if (_autoSwitchDisplayModeSupportedHMDPlugin
|
||||
&& _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
|
||||
|
@ -2993,6 +3016,9 @@ void Application::initializeUi() {
|
|||
if (_window && _window->isFullScreen()) {
|
||||
setFullscreen(nullptr, true);
|
||||
}
|
||||
|
||||
|
||||
setIsInterstitialMode(true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3471,6 +3497,15 @@ bool Application::isServerlessMode() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Application::setIsInterstitialMode(bool interstitialMode) {
|
||||
if (_interstitialMode != interstitialMode) {
|
||||
_interstitialMode = interstitialMode;
|
||||
|
||||
DependencyManager::get<AudioClient>()->setAudioPaused(_interstitialMode);
|
||||
DependencyManager::get<AvatarManager>()->setMyAvatarDataPacketsPaused(_interstitialMode);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::setIsServerlessMode(bool serverlessDomain) {
|
||||
auto tree = getEntities()->getTree();
|
||||
if (tree) {
|
||||
|
@ -3478,9 +3513,9 @@ void Application::setIsServerlessMode(bool serverlessDomain) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::loadServerlessDomain(QUrl domainURL) {
|
||||
void Application::loadServerlessDomain(QUrl domainURL, bool errorDomain) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL));
|
||||
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL), Q_ARG(bool, errorDomain));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3512,8 +3547,11 @@ void Application::loadServerlessDomain(QUrl domainURL) {
|
|||
}
|
||||
|
||||
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
|
||||
nodeList->getDomainHandler().connectedToServerless(namedPaths);
|
||||
|
||||
if (errorDomain) {
|
||||
nodeList->getDomainHandler().loadedErrorDomain(namedPaths);
|
||||
} else {
|
||||
nodeList->getDomainHandler().connectedToServerless(namedPaths);
|
||||
}
|
||||
|
||||
_fullSceneReceivedCounter++;
|
||||
}
|
||||
|
@ -3748,7 +3786,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
|
||||
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event) || isInterstitialMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5535,6 +5573,7 @@ void Application::update(float deltaTime) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_physicsEnabled) {
|
||||
if (!domainLoadingInProgress) {
|
||||
PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
|
||||
|
@ -5555,6 +5594,7 @@ void Application::update(float deltaTime) {
|
|||
// scene is ready to compute its collision shape.
|
||||
if (getMyAvatar()->isReadyForPhysics()) {
|
||||
_physicsEnabled = true;
|
||||
setIsInterstitialMode(false);
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
}
|
||||
}
|
||||
|
@ -5634,7 +5674,7 @@ void Application::update(float deltaTime) {
|
|||
// Transfer the user inputs to the driveKeys
|
||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||
myAvatar->clearDriveKeys();
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT && !isInterstitialMode()) {
|
||||
if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
||||
|
@ -5950,7 +5990,7 @@ void Application::update(float deltaTime) {
|
|||
// send packet containing downstream audio stats to the AudioMixer
|
||||
{
|
||||
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
|
||||
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) {
|
||||
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS && !isInterstitialMode()) {
|
||||
_lastSendDownstreamAudioStats = now;
|
||||
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);
|
||||
|
@ -6113,21 +6153,23 @@ void Application::updateRenderArgs(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::queryAvatars() {
|
||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||
unsigned char* bufferStart = destinationBuffer;
|
||||
if (!isInterstitialMode()) {
|
||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||
unsigned char* bufferStart = destinationBuffer;
|
||||
|
||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
|
||||
for (const auto& view : _conicalViews) {
|
||||
destinationBuffer += view.serialize(destinationBuffer);
|
||||
for (const auto& view : _conicalViews) {
|
||||
destinationBuffer += view.serialize(destinationBuffer);
|
||||
}
|
||||
|
||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6350,6 +6392,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
||||
|
||||
resetPhysicsReadyInformation();
|
||||
setIsInterstitialMode(true);
|
||||
|
||||
_octreeServerSceneStats.withWriteLock([&] {
|
||||
_octreeServerSceneStats.clear();
|
||||
|
@ -6370,10 +6413,6 @@ void Application::clearDomainOctreeDetails() {
|
|||
getMyAvatar()->setAvatarEntityDataChanged(true);
|
||||
}
|
||||
|
||||
void Application::clearDomainAvatars() {
|
||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
||||
}
|
||||
|
||||
void Application::domainURLChanged(QUrl domainURL) {
|
||||
// disable physics until we have enough information about our new location to not cause craziness.
|
||||
resetPhysicsReadyInformation();
|
||||
|
@ -6384,6 +6423,16 @@ void Application::domainURLChanged(QUrl domainURL) {
|
|||
updateWindowTitle();
|
||||
}
|
||||
|
||||
void Application::goToErrorDomainURL(QUrl errorDomainURL) {
|
||||
// disable physics until we have enough information about our new location to not cause craziness.
|
||||
resetPhysicsReadyInformation();
|
||||
setIsServerlessMode(errorDomainURL.scheme() != URL_SCHEME_HIFI);
|
||||
if (isServerlessMode()) {
|
||||
loadServerlessDomain(errorDomainURL, true);
|
||||
}
|
||||
updateWindowTitle();
|
||||
}
|
||||
|
||||
|
||||
void Application::resettingDomain() {
|
||||
_notifiedPacketVersionMismatchThisDomain = false;
|
||||
|
@ -6422,7 +6471,7 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
_octreeQuery.incrementConnectionID();
|
||||
}
|
||||
|
||||
if (node->getType() == NodeType::AudioMixer) {
|
||||
if (node->getType() == NodeType::AudioMixer && !isInterstitialMode()) {
|
||||
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
||||
}
|
||||
|
||||
|
@ -6442,8 +6491,10 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
getMyAvatar()->markIdentityDataChanged();
|
||||
getMyAvatar()->resetLastSent();
|
||||
|
||||
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
||||
getMyAvatar()->sendAvatarDataPacket(true);
|
||||
if (!isInterstitialMode()) {
|
||||
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
||||
getMyAvatar()->sendAvatarDataPacket(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6461,9 +6512,6 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
} else if (node->getType() == NodeType::EntityServer) {
|
||||
// we lost an entity server, clear all of the domain octree details
|
||||
clearDomainOctreeDetails();
|
||||
} else if (node->getType() == NodeType::AvatarMixer) {
|
||||
// our avatar mixer has gone away - clear the hash of avatars
|
||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
||||
} else if (node->getType() == NodeType::AssetServer) {
|
||||
// asset server going away - check if we have the asset browser showing
|
||||
|
||||
|
@ -7797,7 +7845,7 @@ float Application::getRenderResolutionScale() const {
|
|||
}
|
||||
|
||||
void Application::notifyPacketVersionMismatch() {
|
||||
if (!_notifiedPacketVersionMismatchThisDomain) {
|
||||
if (!_notifiedPacketVersionMismatchThisDomain && !isInterstitialMode()) {
|
||||
_notifiedPacketVersionMismatchThisDomain = true;
|
||||
|
||||
QString message = "The location you are visiting is running an incompatible server version.\n";
|
||||
|
|
|
@ -224,6 +224,7 @@ public:
|
|||
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
||||
void setPreferStylusOverLaser(bool value);
|
||||
|
||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||
bool getPreferAvatarFingerOverStylus() { return false; }
|
||||
|
@ -304,6 +305,7 @@ public:
|
|||
void saveNextPhysicsStats(QString filename);
|
||||
|
||||
bool isServerlessMode() const;
|
||||
bool isInterstitialMode() const { return _interstitialMode; }
|
||||
|
||||
void replaceDomainContent(const QString& url);
|
||||
|
||||
|
@ -331,6 +333,8 @@ signals:
|
|||
|
||||
void uploadRequest(QString path);
|
||||
|
||||
void loginDialogPoppedUp();
|
||||
|
||||
public slots:
|
||||
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
||||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
||||
|
@ -338,6 +342,7 @@ public slots:
|
|||
bool importEntities(const QString& url);
|
||||
void updateThreadPoolCount() const;
|
||||
void updateSystemTabletMode();
|
||||
void goToErrorDomainURL(QUrl errorDomainURL);
|
||||
|
||||
Q_INVOKABLE void loadDialog();
|
||||
Q_INVOKABLE void loadScriptURLDialog() const;
|
||||
|
@ -426,7 +431,8 @@ public slots:
|
|||
void setPreferredCursor(const QString& cursor);
|
||||
|
||||
void setIsServerlessMode(bool serverlessDomain);
|
||||
void loadServerlessDomain(QUrl domainURL);
|
||||
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
|
||||
void setIsInterstitialMode(bool interstialMode);
|
||||
|
||||
void updateVerboseLogging();
|
||||
|
||||
|
@ -437,7 +443,6 @@ private slots:
|
|||
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
||||
void showDesktop();
|
||||
void clearDomainOctreeDetails();
|
||||
void clearDomainAvatars();
|
||||
void onAboutToQuit();
|
||||
void onPresent(quint32 frameCount);
|
||||
|
||||
|
@ -626,6 +631,7 @@ private:
|
|||
QHash<int, QKeyEvent> _keysPressed;
|
||||
|
||||
bool _enableProcessOctreeThread;
|
||||
bool _interstitialMode { false };
|
||||
|
||||
OctreePacketProcessor _octreeProcessor;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
|
|
@ -11,16 +11,18 @@
|
|||
|
||||
#include "ConnectionMonitor.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <DomainHandler.h>
|
||||
#include <AddressManager.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
// Because the connection monitor is created at startup, the time we wait on initial load
|
||||
// should be longer to allow the application to initialize.
|
||||
static const int ON_INITIAL_LOAD_DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 10000;
|
||||
static const int DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
||||
static const int ON_INITIAL_LOAD_REDIRECT_AFTER_DISCONNECTED_FOR_X_MS = 10000;
|
||||
static const int REDIRECT_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
||||
|
||||
void ConnectionMonitor::init() {
|
||||
// Connect to domain disconnected message
|
||||
|
@ -30,23 +32,25 @@ void ConnectionMonitor::init() {
|
|||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::startTimer);
|
||||
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &ConnectionMonitor::stopTimer);
|
||||
connect(this, &ConnectionMonitor::setRedirectErrorState, &domainHandler, &DomainHandler::setRedirectErrorState);
|
||||
|
||||
_timer.setSingleShot(true);
|
||||
if (!domainHandler.isConnected()) {
|
||||
_timer.start(ON_INITIAL_LOAD_DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start(ON_INITIAL_LOAD_REDIRECT_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
}
|
||||
|
||||
connect(&_timer, &QTimer::timeout, this, []() {
|
||||
qDebug() << "ConnectionMonitor: Showing connection failure window";
|
||||
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(true);
|
||||
connect(&_timer, &QTimer::timeout, this, [this]() {
|
||||
qDebug() << "ConnectionMonitor: Redirecting to 404 error domain";
|
||||
// set in a timeout error
|
||||
emit setRedirectErrorState(REDIRECT_HIFI_ADDRESS, 5);
|
||||
});
|
||||
}
|
||||
|
||||
void ConnectionMonitor::startTimer() {
|
||||
_timer.start(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start(REDIRECT_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::stopTimer() {
|
||||
_timer.stop();
|
||||
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(false);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
class QUrl;
|
||||
class QString;
|
||||
|
||||
class ConnectionMonitor : public QObject {
|
||||
|
@ -22,6 +23,9 @@ class ConnectionMonitor : public QObject {
|
|||
public:
|
||||
void init();
|
||||
|
||||
signals:
|
||||
void setRedirectErrorState(QUrl errorURL, int reasonCode);
|
||||
|
||||
private slots:
|
||||
void startTimer();
|
||||
void stopTimer();
|
||||
|
|
|
@ -137,7 +137,7 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
|||
quint64 now = usecTimestampNow();
|
||||
quint64 dt = now - _lastSendAvatarDataTime;
|
||||
|
||||
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS) {
|
||||
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused) {
|
||||
// send head/hand data to the avatar mixer and voxel server
|
||||
PerformanceTimer perfTimer("send");
|
||||
_myAvatar->sendAvatarDataPacket();
|
||||
|
@ -155,6 +155,16 @@ float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& ra
|
|||
return avatar ? avatar->getDataRate(rateName) : 0.0f;
|
||||
}
|
||||
|
||||
void AvatarManager::setMyAvatarDataPacketsPaused(bool pause) {
|
||||
if (_myAvatarDataPacketsPaused != pause) {
|
||||
_myAvatarDataPacketsPaused = pause;
|
||||
|
||||
if (!_myAvatarDataPacketsPaused) {
|
||||
_myAvatar->sendAvatarDataPacket(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) const {
|
||||
auto avatar = getAvatarBySessionID(sessionID);
|
||||
return avatar ? avatar->getUpdateRate(rateName) : 0.0f;
|
||||
|
@ -802,13 +812,13 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
|
|||
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
||||
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
||||
QJsonObject thisAvatarPalData;
|
||||
|
||||
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
||||
currentSessionUUID = "";
|
||||
}
|
||||
|
||||
|
||||
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
||||
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
||||
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
||||
|
|
|
@ -91,9 +91,11 @@ public:
|
|||
void updateOtherAvatars(float deltaTime);
|
||||
void sendIdentityRequest(const QUuid& avatarID) const;
|
||||
|
||||
void setMyAvatarDataPacketsPaused(bool puase);
|
||||
|
||||
void postUpdate(float deltaTime, const render::ScenePointer& scene);
|
||||
|
||||
void clearOtherAvatars();
|
||||
void clearOtherAvatars() override;
|
||||
void deleteAllAvatars();
|
||||
|
||||
void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates);
|
||||
|
@ -219,6 +221,7 @@ private:
|
|||
int _numAvatarsNotUpdated { 0 };
|
||||
float _avatarSimulationTime { 0.0f };
|
||||
bool _shouldRender { true };
|
||||
bool _myAvatarDataPacketsPaused { false };
|
||||
mutable int _identityRequestsSent { 0 };
|
||||
|
||||
mutable std::mutex _spaceLock;
|
||||
|
|
|
@ -11,6 +11,25 @@
|
|||
|
||||
#include "AvatarMotionState.h"
|
||||
|
||||
static xColor getLoadingOrbColor(Avatar::LoadingStatus loadingStatus) {
|
||||
|
||||
const xColor NO_MODEL_COLOR(0xe3, 0xe3, 0xe3);
|
||||
const xColor LOAD_MODEL_COLOR(0xef, 0x93, 0xd1);
|
||||
const xColor LOAD_SUCCESS_COLOR(0x1f, 0xc6, 0xa6);
|
||||
const xColor LOAD_FAILURE_COLOR(0xc6, 0x21, 0x47);
|
||||
switch (loadingStatus) {
|
||||
case Avatar::LoadingStatus::NoModel:
|
||||
return NO_MODEL_COLOR;
|
||||
case Avatar::LoadingStatus::LoadModel:
|
||||
return LOAD_MODEL_COLOR;
|
||||
case Avatar::LoadingStatus::LoadSuccess:
|
||||
return LOAD_SUCCESS_COLOR;
|
||||
case Avatar::LoadingStatus::LoadFailure:
|
||||
default:
|
||||
return LOAD_FAILURE_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = new Head(this);
|
||||
|
@ -48,7 +67,7 @@ void OtherAvatar::createOrb() {
|
|||
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
|
||||
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
|
||||
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
|
||||
_otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF });
|
||||
_otherAvatarOrbMeshPlaceholder->setColor(getLoadingOrbColor(_loadingStatus));
|
||||
_otherAvatarOrbMeshPlaceholder->setIsSolid(false);
|
||||
_otherAvatarOrbMeshPlaceholder->setPulseMin(0.5);
|
||||
_otherAvatarOrbMeshPlaceholder->setPulseMax(1.0);
|
||||
|
@ -64,6 +83,13 @@ void OtherAvatar::createOrb() {
|
|||
}
|
||||
}
|
||||
|
||||
void OtherAvatar::indicateLoadingStatus(LoadingStatus loadingStatus) {
|
||||
Avatar::indicateLoadingStatus(loadingStatus);
|
||||
if (_otherAvatarOrbMeshPlaceholder) {
|
||||
_otherAvatarOrbMeshPlaceholder->setColor(getLoadingOrbColor(_loadingStatus));
|
||||
}
|
||||
}
|
||||
|
||||
void OtherAvatar::setSpaceIndex(int32_t index) {
|
||||
assert(_spaceIndex == -1);
|
||||
_spaceIndex = index;
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
|
||||
virtual void instantiableAvatar() override { };
|
||||
virtual void createOrb() override;
|
||||
virtual void indicateLoadingStatus(LoadingStatus loadingStatus) override;
|
||||
void updateOrbPosition();
|
||||
void removeOrb();
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
#include "SafeLanding.h"
|
||||
|
||||
OctreePacketProcessor::OctreePacketProcessor():
|
||||
_safeLanding(new SafeLanding())
|
||||
|
@ -133,7 +132,3 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
|
|||
void OctreePacketProcessor::startEntitySequence() {
|
||||
_safeLanding->startEntitySequence(qApp->getEntities());
|
||||
}
|
||||
|
||||
bool OctreePacketProcessor::isLoadSequenceComplete() const {
|
||||
return _safeLanding->isLoadSequenceComplete();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <ReceivedPacketProcessor.h>
|
||||
#include <ReceivedMessage.h>
|
||||
|
||||
class SafeLanding;
|
||||
#include "SafeLanding.h"
|
||||
|
||||
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
|
||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||
|
@ -26,7 +26,8 @@ public:
|
|||
~OctreePacketProcessor();
|
||||
|
||||
void startEntitySequence();
|
||||
bool isLoadSequenceComplete() const;
|
||||
bool isLoadSequenceComplete() const { return _safeLanding->isLoadSequenceComplete(); }
|
||||
float domainLoadingProgress() const { return _safeLanding->loadingProgressPercentage(); }
|
||||
|
||||
signals:
|
||||
void packetVersionMismatch();
|
||||
|
@ -40,4 +41,4 @@ private slots:
|
|||
private:
|
||||
std::unique_ptr<SafeLanding> _safeLanding;
|
||||
};
|
||||
#endif // hifi_OctreePacketProcessor_h
|
||||
#endif // hifi_OctreePacketProcessor_h
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "EntityTreeRenderer.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "Application.h"
|
||||
|
||||
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
||||
|
||||
|
@ -53,6 +54,7 @@ void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityT
|
|||
void SafeLanding::stopEntitySequence() {
|
||||
Locker lock(_lock);
|
||||
_trackingEntities = false;
|
||||
_maxTrackedEntityCount = 0;
|
||||
_initialStart = INVALID_SEQUENCE;
|
||||
_initialEnd = INVALID_SEQUENCE;
|
||||
_trackedEntities.clear();
|
||||
|
@ -64,20 +66,13 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
|
|||
Locker lock(_lock);
|
||||
EntityItemPointer entity = _entityTree->findEntityByID(entityID);
|
||||
|
||||
if (entity && !entity->getCollisionless()) {
|
||||
const auto& entityType = entity->getType();
|
||||
if (entityType == EntityTypes::Model) {
|
||||
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
|
||||
static const std::set<ShapeType> downloadedCollisionTypes
|
||||
{ SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, SHAPE_TYPE_SIMPLE_HULL };
|
||||
bool hasAABox;
|
||||
entity->getAABox(hasAABox);
|
||||
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
|
||||
// Only track entities with downloaded collision bodies.
|
||||
_trackedEntities.emplace(entityID, entity);
|
||||
}
|
||||
}
|
||||
_trackedEntities.emplace(entityID, entity);
|
||||
int trackedEntityCount = (int)_trackedEntities.size();
|
||||
|
||||
if (trackedEntityCount > _maxTrackedEntityCount) {
|
||||
_maxTrackedEntityCount = trackedEntityCount;
|
||||
}
|
||||
qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +97,7 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) {
|
|||
}
|
||||
|
||||
bool SafeLanding::isLoadSequenceComplete() {
|
||||
if (isEntityPhysicsComplete() && isSequenceNumbersComplete()) {
|
||||
if (isEntityLoadingComplete() && isSequenceNumbersComplete()) {
|
||||
Locker lock(_lock);
|
||||
_trackedEntities.clear();
|
||||
_initialStart = INVALID_SEQUENCE;
|
||||
|
@ -114,6 +109,15 @@ bool SafeLanding::isLoadSequenceComplete() {
|
|||
return !_trackingEntities;
|
||||
}
|
||||
|
||||
float SafeLanding::loadingProgressPercentage() {
|
||||
Locker lock(_lock);
|
||||
if (_maxTrackedEntityCount > 0) {
|
||||
return ((_maxTrackedEntityCount - _trackedEntities.size()) / (float)_maxTrackedEntityCount);
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool SafeLanding::isSequenceNumbersComplete() {
|
||||
if (_initialStart != INVALID_SEQUENCE) {
|
||||
Locker lock(_lock);
|
||||
|
@ -132,17 +136,42 @@ bool SafeLanding::isSequenceNumbersComplete() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SafeLanding::isEntityPhysicsComplete() {
|
||||
Locker lock(_lock);
|
||||
for (auto entityMapIter = _trackedEntities.begin(); entityMapIter != _trackedEntities.end(); ++entityMapIter) {
|
||||
auto entity = entityMapIter->second;
|
||||
if (!entity->shouldBePhysical() || entity->isReadyToComputeShape()) {
|
||||
entityMapIter = _trackedEntities.erase(entityMapIter);
|
||||
if (entityMapIter == _trackedEntities.end()) {
|
||||
break;
|
||||
bool isEntityPhysicsReady(const EntityItemPointer& entity) {
|
||||
if (entity && !entity->getCollisionless()) {
|
||||
const auto& entityType = entity->getType();
|
||||
if (entityType == EntityTypes::Model) {
|
||||
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
|
||||
static const std::set<ShapeType> downloadedCollisionTypes
|
||||
{ SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, SHAPE_TYPE_SIMPLE_HULL };
|
||||
bool hasAABox;
|
||||
entity->getAABox(hasAABox);
|
||||
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
|
||||
return entity->isReadyToComputeShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SafeLanding::isEntityLoadingComplete() {
|
||||
Locker lock(_lock);
|
||||
auto entityTree = qApp->getEntities();
|
||||
auto entityMapIter = _trackedEntities.begin();
|
||||
|
||||
while (entityMapIter != _trackedEntities.end()) {
|
||||
auto entity = entityMapIter->second;
|
||||
bool isVisuallyReady = (entity->isVisuallyReady() || !entityTree->renderableForEntityId(entityMapIter->first));
|
||||
if (isEntityPhysicsReady(entity) && isVisuallyReady) {
|
||||
entityMapIter = _trackedEntities.erase(entityMapIter);
|
||||
} else {
|
||||
if (!isVisuallyReady) {
|
||||
entity->requestRenderUpdate();
|
||||
}
|
||||
|
||||
entityMapIter++;
|
||||
}
|
||||
}
|
||||
return _trackedEntities.empty();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityDynamicInterface.h"
|
||||
|
||||
class EntityTreeRenderer;
|
||||
class EntityItemID;
|
||||
|
@ -29,6 +30,7 @@ public:
|
|||
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
||||
void noteReceivedsequenceNumber(int sequenceNumber);
|
||||
bool isLoadSequenceComplete();
|
||||
float loadingProgressPercentage();
|
||||
|
||||
private slots:
|
||||
void addTrackedEntity(const EntityItemID& entityID);
|
||||
|
@ -37,7 +39,7 @@ private slots:
|
|||
private:
|
||||
bool isSequenceNumbersComplete();
|
||||
void debugDumpSequenceIDs() const;
|
||||
bool isEntityPhysicsComplete();
|
||||
bool isEntityLoadingComplete();
|
||||
|
||||
std::mutex _lock;
|
||||
using Locker = std::lock_guard<std::mutex>;
|
||||
|
@ -49,6 +51,7 @@ private:
|
|||
static constexpr int INVALID_SEQUENCE = -1;
|
||||
int _initialStart { INVALID_SEQUENCE };
|
||||
int _initialEnd { INVALID_SEQUENCE };
|
||||
int _maxTrackedEntityCount { 0 };
|
||||
|
||||
struct SequenceLessThan {
|
||||
bool operator()(const int& a, const int& b) const;
|
||||
|
|
|
@ -409,6 +409,10 @@ glm::vec2 WindowScriptingInterface::getDeviceSize() const {
|
|||
return qApp->getDeviceSize();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getLastDomainConnectionError() const {
|
||||
return DependencyManager::get<NodeList>()->getDomainHandler().getLastDomainConnectionError();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getX() {
|
||||
return qApp->getWindow()->geometry().x();
|
||||
}
|
||||
|
@ -584,3 +588,8 @@ void WindowScriptingInterface::onMessageBoxSelected(int button) {
|
|||
_messageBoxes.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float WindowScriptingInterface::domainLoadingProgress() {
|
||||
return qApp->getOctreePacketProcessor().domainLoadingProgress();
|
||||
}
|
||||
|
|
|
@ -491,6 +491,13 @@ public slots:
|
|||
*/
|
||||
glm::vec2 getDeviceSize() const;
|
||||
|
||||
/**jsdoc
|
||||
* Gets the last domain connection error when a connection is refused.
|
||||
* @function Window.getLastDomainConnectionError
|
||||
* @returns {Window.ConnectionRefusedReason} Integer number that enumerates the last domain connection refused.
|
||||
*/
|
||||
int getLastDomainConnectionError() const;
|
||||
|
||||
/**jsdoc
|
||||
* Open a non-modal message box that can have a variety of button combinations. See also,
|
||||
* {@link Window.updateMessageBox|updateMessageBox} and {@link Window.closeMessageBox|closeMessageBox}.
|
||||
|
@ -561,6 +568,8 @@ public slots:
|
|||
*/
|
||||
void closeMessageBox(int id);
|
||||
|
||||
float domainLoadingProgress();
|
||||
|
||||
private slots:
|
||||
void onWindowGeometryChanged(const QRect& geometry);
|
||||
void onMessageBoxSelected(int button);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/SteamClientPlugin.h>
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include "DependencyManager.h"
|
||||
|
@ -37,11 +38,19 @@ LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
|
|||
connect(accountManager.data(), &AccountManager::loginFailed,
|
||||
this, &LoginDialog::handleLoginFailed);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void LoginDialog::showWithSelection()
|
||||
{
|
||||
LoginDialog::~LoginDialog() {
|
||||
Setting::Handle<bool> loginDialogPoppedUp{ "loginDialogPoppedUp", false };
|
||||
if (loginDialogPoppedUp.get()) {
|
||||
QJsonObject data;
|
||||
data["action"] = "user opted out";
|
||||
UserActivityLogger::getInstance().logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginDialogPoppedUp.set(false);
|
||||
}
|
||||
|
||||
void LoginDialog::showWithSelection() {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
|
@ -73,9 +82,7 @@ void LoginDialog::toggleAction() {
|
|||
} else {
|
||||
// change the menu item to login
|
||||
loginAction->setText("Login / Sign Up");
|
||||
connection = connect(loginAction, &QAction::triggered, [] {
|
||||
LoginDialog::showWithSelection();
|
||||
});
|
||||
connection = connect(loginAction, &QAction::triggered, [] { LoginDialog::showWithSelection(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +165,6 @@ void LoginDialog::createAccountFromStream(QString username) {
|
|||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString& url) const {
|
||||
|
@ -200,25 +206,24 @@ void LoginDialog::createFailed(QNetworkReply* reply) {
|
|||
}
|
||||
|
||||
void LoginDialog::signup(const QString& email, const QString& username, const QString& password) {
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "signupCompleted";
|
||||
callbackParams.errorCallbackMethod = "signupFailed";
|
||||
|
||||
|
||||
QJsonObject payload;
|
||||
|
||||
|
||||
QJsonObject userObject;
|
||||
userObject.insert("email", email);
|
||||
userObject.insert("username", username);
|
||||
userObject.insert("password", password);
|
||||
|
||||
|
||||
payload.insert("user", userObject);
|
||||
|
||||
|
||||
static const QString API_SIGNUP_PATH = "api/v1/users";
|
||||
|
||||
|
||||
qDebug() << "Sending a request to create an account for" << username;
|
||||
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(API_SIGNUP_PATH, AccountManagerAuth::None,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
|
@ -240,41 +245,37 @@ QString errorStringFromAPIObject(const QJsonValue& apiObject) {
|
|||
}
|
||||
|
||||
void LoginDialog::signupFailed(QNetworkReply* reply) {
|
||||
|
||||
// parse the returned JSON to see what the problem was
|
||||
auto jsonResponse = QJsonDocument::fromJson(reply->readAll());
|
||||
|
||||
|
||||
static const QString RESPONSE_DATA_KEY = "data";
|
||||
|
||||
|
||||
auto dataJsonValue = jsonResponse.object()[RESPONSE_DATA_KEY];
|
||||
|
||||
|
||||
if (dataJsonValue.isObject()) {
|
||||
auto dataObject = dataJsonValue.toObject();
|
||||
|
||||
|
||||
static const QString EMAIL_DATA_KEY = "email";
|
||||
static const QString USERNAME_DATA_KEY = "username";
|
||||
static const QString PASSWORD_DATA_KEY = "password";
|
||||
|
||||
|
||||
QStringList errorStringList;
|
||||
|
||||
|
||||
if (dataObject.contains(EMAIL_DATA_KEY)) {
|
||||
errorStringList.append(QString("Email %1.").arg(errorStringFromAPIObject(dataObject[EMAIL_DATA_KEY])));
|
||||
}
|
||||
|
||||
|
||||
if (dataObject.contains(USERNAME_DATA_KEY)) {
|
||||
errorStringList.append(QString("Username %1.").arg(errorStringFromAPIObject(dataObject[USERNAME_DATA_KEY])));
|
||||
}
|
||||
|
||||
|
||||
if (dataObject.contains(PASSWORD_DATA_KEY)) {
|
||||
errorStringList.append(QString("Password %1.").arg(errorStringFromAPIObject(dataObject[PASSWORD_DATA_KEY])));
|
||||
}
|
||||
|
||||
|
||||
emit handleSignupFailed(errorStringList.join('\n'));
|
||||
} else {
|
||||
static const QString DEFAULT_SIGN_UP_FAILURE_MESSAGE = "There was an unknown error while creating your account. Please try again later.";
|
||||
emit handleSignupFailed(DEFAULT_SIGN_UP_FAILURE_MESSAGE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,10 @@ public:
|
|||
|
||||
LoginDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
~LoginDialog();
|
||||
|
||||
static void showWithSelection();
|
||||
|
||||
signals:
|
||||
void handleLoginCompleted();
|
||||
void handleLoginFailed();
|
||||
|
@ -62,7 +65,6 @@ protected slots:
|
|||
Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
|
||||
|
||||
Q_INVOKABLE void openUrl(const QString& url) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -106,6 +106,10 @@ extern std::atomic<size_t> DECIMATED_TEXTURE_COUNT;
|
|||
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
|
||||
|
||||
void Stats::updateStats(bool force) {
|
||||
|
||||
if (qApp->isInterstitialMode()) {
|
||||
return;
|
||||
}
|
||||
QQuickItem* parent = parentItem();
|
||||
if (!force) {
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
|
|
|
@ -305,6 +305,16 @@ void AudioClient::audioMixerKilled() {
|
|||
emit disconnected();
|
||||
}
|
||||
|
||||
void AudioClient::setAudioPaused(bool pause) {
|
||||
if (_audioPaused != pause) {
|
||||
_audioPaused = pause;
|
||||
|
||||
if (!_audioPaused) {
|
||||
negotiateAudioFormat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||
QAudioDeviceInfo result;
|
||||
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
||||
|
@ -651,7 +661,6 @@ void AudioClient::stop() {
|
|||
}
|
||||
|
||||
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
char bitset;
|
||||
message->readPrimitive(&bitset);
|
||||
|
||||
|
@ -664,11 +673,10 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessag
|
|||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||
} else {
|
||||
_receivedAudioStream.clearReverb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
if (message->getType() == PacketType::SilentAudioFrame) {
|
||||
_silentInbound.increment();
|
||||
} else {
|
||||
|
@ -1026,80 +1034,82 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
|||
}
|
||||
|
||||
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||
if (_muted) {
|
||||
_lastInputLoudness = 0.0f;
|
||||
_timeSinceLastClip = 0.0f;
|
||||
} else {
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
// The audio gate includes DC removal
|
||||
_audioGate->render(samples, samples, numFrames);
|
||||
} else {
|
||||
_audioGate->removeDC(samples, samples, numFrames);
|
||||
}
|
||||
|
||||
int32_t loudness = 0;
|
||||
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
||||
bool didClip = false;
|
||||
for (int i = 0; i < numSamples; ++i) {
|
||||
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
||||
int32_t sample = std::abs((int32_t)samples[i]);
|
||||
loudness += sample;
|
||||
didClip |= (sample > CLIPPING_THRESHOLD);
|
||||
}
|
||||
_lastInputLoudness = (float)loudness / numSamples;
|
||||
|
||||
if (didClip) {
|
||||
if (!_audioPaused) {
|
||||
if (_muted) {
|
||||
_lastInputLoudness = 0.0f;
|
||||
_timeSinceLastClip = 0.0f;
|
||||
} else if (_timeSinceLastClip >= 0.0f) {
|
||||
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
||||
} else {
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
// The audio gate includes DC removal
|
||||
_audioGate->render(samples, samples, numFrames);
|
||||
} else {
|
||||
_audioGate->removeDC(samples, samples, numFrames);
|
||||
}
|
||||
|
||||
int32_t loudness = 0;
|
||||
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
||||
bool didClip = false;
|
||||
for (int i = 0; i < numSamples; ++i) {
|
||||
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
||||
int32_t sample = std::abs((int32_t)samples[i]);
|
||||
loudness += sample;
|
||||
didClip |= (sample > CLIPPING_THRESHOLD);
|
||||
}
|
||||
_lastInputLoudness = (float)loudness / numSamples;
|
||||
|
||||
if (didClip) {
|
||||
_timeSinceLastClip = 0.0f;
|
||||
} else if (_timeSinceLastClip >= 0.0f) {
|
||||
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
||||
}
|
||||
|
||||
emit inputReceived(audioBuffer);
|
||||
}
|
||||
|
||||
emit inputReceived(audioBuffer);
|
||||
emit inputLoudnessChanged(_lastInputLoudness);
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||
_audioGateOpen = audioGateOpen;
|
||||
|
||||
if (openedInLastBlock) {
|
||||
emit noiseGateOpened();
|
||||
} else if (closedInLastBlock) {
|
||||
emit noiseGateClosed();
|
||||
}
|
||||
|
||||
// the codec must be flushed to silence before sending silent packets,
|
||||
// so delay the transition to silent packets by one packet after becoming silent.
|
||||
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
||||
if (!audioGateOpen && !closedInLastBlock) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
_silentOutbound.increment();
|
||||
} else {
|
||||
_audioOutbound.increment();
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
audioTransform.setTranslation(_positionGetter());
|
||||
audioTransform.setRotation(_orientationGetter());
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audioBuffer, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audioBuffer;
|
||||
}
|
||||
|
||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||
packetType, _selectedCodecName);
|
||||
_stats.sentPacket();
|
||||
}
|
||||
|
||||
emit inputLoudnessChanged(_lastInputLoudness);
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||
_audioGateOpen = audioGateOpen;
|
||||
|
||||
if (openedInLastBlock) {
|
||||
emit noiseGateOpened();
|
||||
} else if (closedInLastBlock) {
|
||||
emit noiseGateClosed();
|
||||
}
|
||||
|
||||
// the codec must be flushed to silence before sending silent packets,
|
||||
// so delay the transition to silent packets by one packet after becoming silent.
|
||||
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
||||
if (!audioGateOpen && !closedInLastBlock) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
_silentOutbound.increment();
|
||||
} else {
|
||||
_audioOutbound.increment();
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
audioTransform.setTranslation(_positionGetter());
|
||||
audioTransform.setRotation(_orientationGetter());
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audioBuffer, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audioBuffer;
|
||||
}
|
||||
|
||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||
packetType, _selectedCodecName);
|
||||
_stats.sentPacket();
|
||||
}
|
||||
|
||||
void AudioClient::handleMicAudioInput() {
|
||||
|
|
|
@ -162,6 +162,7 @@ public:
|
|||
|
||||
bool startRecording(const QString& filename);
|
||||
void stopRecording();
|
||||
void setAudioPaused(bool pause);
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -416,6 +417,7 @@ private:
|
|||
QVector<AudioInjectorPointer> _activeLocalAudioInjectors;
|
||||
|
||||
bool _isPlayingBackRecording { false };
|
||||
bool _audioPaused { false };
|
||||
|
||||
CodecPluginPointer _codec;
|
||||
QString _selectedCodecName;
|
||||
|
|
|
@ -126,6 +126,8 @@ Avatar::Avatar(QThread* thread) :
|
|||
_leftPointerGeometryID = geometryCache->allocateID();
|
||||
_rightPointerGeometryID = geometryCache->allocateID();
|
||||
_lastRenderUpdateTime = usecTimestampNow();
|
||||
|
||||
indicateLoadingStatus(LoadingStatus::NoModel);
|
||||
}
|
||||
|
||||
Avatar::~Avatar() {
|
||||
|
@ -1370,12 +1372,15 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
|
|||
}
|
||||
|
||||
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
if (!isMyAvatar()) {
|
||||
createOrb();
|
||||
}
|
||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||
if (QThread::currentThread() == thread()) {
|
||||
|
||||
if (!isMyAvatar()) {
|
||||
createOrb();
|
||||
}
|
||||
|
||||
_skeletonModel->setURL(_skeletonModelURL);
|
||||
indicateLoadingStatus(LoadingStatus::LoadModel);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, _skeletonModelURL));
|
||||
}
|
||||
|
@ -1388,11 +1393,12 @@ void Avatar::setModelURLFinished(bool success) {
|
|||
_reconstructSoftEntitiesJointMap = true;
|
||||
|
||||
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
|
||||
indicateLoadingStatus(LoadingStatus::LoadFailure);
|
||||
const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts
|
||||
if (_skeletonModel->getResourceDownloadAttemptsRemaining() <= 0 ||
|
||||
_skeletonModel->getResourceDownloadAttempts() > MAX_SKELETON_DOWNLOAD_ATTEMPTS) {
|
||||
qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL
|
||||
<< "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts.";
|
||||
<< "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts.";
|
||||
// call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that
|
||||
// we don't redo this every time we receive an identity packet from the avatar with the bad url.
|
||||
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL",
|
||||
|
@ -1403,6 +1409,9 @@ void Avatar::setModelURLFinished(bool success) {
|
|||
<< "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
indicateLoadingStatus(LoadingStatus::LoadSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
// rig is ready
|
||||
|
|
|
@ -107,6 +107,14 @@ public:
|
|||
virtual bool isMyAvatar() const override { return false; }
|
||||
virtual void createOrb() { }
|
||||
|
||||
enum class LoadingStatus {
|
||||
NoModel,
|
||||
LoadModel,
|
||||
LoadSuccess,
|
||||
LoadFailure
|
||||
};
|
||||
virtual void indicateLoadingStatus(LoadingStatus loadingStatus) { _loadingStatus = loadingStatus; }
|
||||
|
||||
virtual QVector<glm::quat> getJointRotations() const override;
|
||||
using AvatarData::getJointRotation;
|
||||
virtual glm::quat getJointRotation(int index) const override;
|
||||
|
@ -540,6 +548,8 @@ protected:
|
|||
static const float MYAVATAR_LOADING_PRIORITY;
|
||||
static const float OTHERAVATAR_LOADING_PRIORITY;
|
||||
static const float ATTACHMENT_LOADING_PRIORITY;
|
||||
|
||||
LoadingStatus _loadingStatus { LoadingStatus::NoModel };
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -113,6 +113,12 @@ AvatarHashMap::AvatarHashMap() {
|
|||
packetReceiver.registerListener(PacketType::BulkAvatarTraits, this, "processBulkAvatarTraits");
|
||||
|
||||
connect(nodeList.data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, [this](SharedNodePointer killedNode){
|
||||
if (killedNode->getType() == NodeType::AvatarMixer) {
|
||||
clearOtherAvatars();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QVector<QUuid> AvatarHashMap::getAvatarIdentifiers() {
|
||||
|
@ -429,3 +435,12 @@ void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& ol
|
|||
emit avatarSessionChangedEvent(sessionUUID, oldUUID);
|
||||
}
|
||||
|
||||
void AvatarHashMap::clearOtherAvatars() {
|
||||
QWriteLocker locker(&_hashLock);
|
||||
|
||||
for (auto& av : _avatarHash) {
|
||||
handleRemovedAvatar(av);
|
||||
}
|
||||
|
||||
_avatarHash.clear();
|
||||
}
|
||||
|
|
|
@ -101,6 +101,8 @@ public:
|
|||
void setReplicaCount(int count);
|
||||
int getReplicaCount() { return _replicas.getReplicaCount(); };
|
||||
|
||||
virtual void clearOtherAvatars();
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -1297,9 +1297,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
});
|
||||
|
||||
// Check for removal
|
||||
ModelPointer model;
|
||||
withReadLock([&] { model = _model; });
|
||||
|
||||
withWriteLock([&] {
|
||||
bool visuallyReady = true;
|
||||
if (_hasModel) {
|
||||
if (model && _didLastVisualGeometryRequestSucceed) {
|
||||
visuallyReady = (_prevModelLoaded && _texturesLoaded);
|
||||
}
|
||||
}
|
||||
entity->setVisuallyReady(visuallyReady);
|
||||
});
|
||||
|
||||
// Check for removal
|
||||
if (!_hasModel) {
|
||||
if (model) {
|
||||
model->removeFromScene(scene, transaction);
|
||||
|
@ -1441,11 +1452,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
// That is where _currentFrame and _lastAnimated were updated.
|
||||
if (_animating) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
||||
|
||||
|
||||
if (!jointsMapped()) {
|
||||
mapJoints(entity, model->getJointNames());
|
||||
//else the joint have been mapped before but we have a new animation to load
|
||||
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
|
||||
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
|
||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(entity->getAnimationURL());
|
||||
_jointMappingCompleted = false;
|
||||
mapJoints(entity, model->getJointNames());
|
||||
|
|
|
@ -288,6 +288,17 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
updateHazeFromEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
bool visuallyReady = true;
|
||||
uint32_t skyboxMode = entity->getSkyboxMode();
|
||||
if (skyboxMode == COMPONENT_MODE_ENABLED && !_skyboxTextureURL.isEmpty()) {
|
||||
bool skyboxLoadedOrFailed = (_skyboxTexture && (_skyboxTexture->isLoaded() || _skyboxTexture->isFailed()));
|
||||
|
||||
visuallyReady = skyboxLoadedOrFailed;
|
||||
}
|
||||
|
||||
entity->setVisuallyReady(visuallyReady);
|
||||
|
||||
if (bloomChanged) {
|
||||
updateBloomFromEntity(entity);
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ public:
|
|||
void setDynamic(bool value);
|
||||
|
||||
virtual bool shouldBePhysical() const { return false; }
|
||||
bool isVisuallyReady() const { return _visuallyReady; }
|
||||
|
||||
bool getLocked() const;
|
||||
void setLocked(bool value);
|
||||
|
@ -527,6 +528,7 @@ public:
|
|||
void removeCloneID(const QUuid& cloneID);
|
||||
const QVector<QUuid> getCloneIDs() const;
|
||||
void setCloneIDs(const QVector<QUuid>& cloneIDs);
|
||||
void setVisuallyReady(bool visuallyReady) { _visuallyReady = visuallyReady; }
|
||||
|
||||
signals:
|
||||
void requestRenderUpdate();
|
||||
|
@ -639,6 +641,7 @@ protected:
|
|||
EntityTreeElementPointer _element; // set by EntityTreeElement
|
||||
void* _physicsInfo { nullptr }; // set by EntitySimulation
|
||||
bool _simulated { false }; // set by EntitySimulation
|
||||
bool _visuallyReady { true };
|
||||
|
||||
bool addActionInternal(EntitySimulationPointer simulation, EntityDynamicPointer action);
|
||||
bool removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation = nullptr);
|
||||
|
|
|
@ -40,6 +40,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(
|
|||
_type = EntityTypes::Model;
|
||||
_lastKnownCurrentFrame = -1;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
_visuallyReady = false;
|
||||
}
|
||||
|
||||
const QString ModelEntityItem::getTextures() const {
|
||||
|
|
|
@ -42,6 +42,7 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en
|
|||
|
||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||
_compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
|
||||
_visuallyReady = false;
|
||||
}
|
||||
|
||||
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||
|
|
|
@ -25,15 +25,15 @@ static bool timeElapsed = false;
|
|||
#endif
|
||||
|
||||
void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
PROFILE_RANGE_BEGIN(render_gpu_gl_detail, glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00);
|
||||
|
||||
++_queryStage._rangeQueryDepth;
|
||||
glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime);
|
||||
glquery->_batchElapsedTimeBegin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
#if !defined(USE_GLES)
|
||||
if (timeElapsed) {
|
||||
if (_queryStage._rangeQueryDepth <= MAX_RANGE_QUERY_DEPTH) {
|
||||
glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo);
|
||||
|
@ -41,17 +41,18 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
|||
} else {
|
||||
glQueryCounter(glquery->_beginqo, GL_TIMESTAMP);
|
||||
}
|
||||
#endif
|
||||
|
||||
glquery->_rangeQueryDepth = _queryStage._rangeQueryDepth;
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
#if !defined(USE_GLES)
|
||||
if (timeElapsed) {
|
||||
if (_queryStage._rangeQueryDepth <= MAX_RANGE_QUERY_DEPTH) {
|
||||
glEndQuery(GL_TIME_ELAPSED);
|
||||
|
@ -59,27 +60,26 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
|||
} else {
|
||||
glQueryCounter(glquery->_endqo, GL_TIMESTAMP);
|
||||
}
|
||||
#endif
|
||||
|
||||
--_queryStage._rangeQueryDepth;
|
||||
GLint64 now;
|
||||
glGetInteger64v(GL_TIMESTAMP, &now);
|
||||
glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
|
||||
auto duration_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - glquery->_batchElapsedTimeBegin);
|
||||
glquery->_batchElapsedTime = duration_ns.count();
|
||||
|
||||
PROFILE_RANGE_END(render_gpu_gl_detail, glquery->_profileRangeId);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
if (glquery->_rangeQueryDepth > MAX_RANGE_QUERY_DEPTH) {
|
||||
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
|
||||
} else {
|
||||
#if !defined(USE_GLES)
|
||||
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
|
||||
if (glquery->_result == GL_TRUE) {
|
||||
if (timeElapsed) {
|
||||
|
@ -92,10 +92,13 @@ void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
|
||||
}
|
||||
#else
|
||||
// gles3 is not supporting true time query returns just the batch elapsed time
|
||||
query->triggerReturnHandler(0, glquery->_batchElapsedTime);
|
||||
#endif
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::resetQueryStage() {
|
||||
|
|
|
@ -47,8 +47,9 @@ public:
|
|||
|
||||
const GLuint& _endqo = { _id };
|
||||
const GLuint _beginqo = { 0 };
|
||||
GLuint64 _result { (GLuint64)-1 };
|
||||
GLuint64 _batchElapsedTime { (GLuint64) 0 };
|
||||
GLuint64 _result { (GLuint64)0 };
|
||||
GLuint64 _batchElapsedTime{ (GLuint64)0 };
|
||||
std::chrono::high_resolution_clock::time_point _batchElapsedTimeBegin;
|
||||
uint64_t _profileRangeId { 0 };
|
||||
uint32_t _rangeQueryDepth { 0 };
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "udt/PacketHeaders.h"
|
||||
|
||||
const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json";
|
||||
const QString REDIRECT_HIFI_ADDRESS = "file:///~/serverless/redirect.json";
|
||||
const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager";
|
||||
const QString SETTINGS_CURRENT_ADDRESS_KEY = "address";
|
||||
|
||||
|
@ -111,6 +112,9 @@ QUrl AddressManager::currentFacingPublicAddress() const {
|
|||
return shareableAddress;
|
||||
}
|
||||
|
||||
QUrl AddressManager::lastAddress() const {
|
||||
return _lastVisitedURL;
|
||||
}
|
||||
|
||||
void AddressManager::loadSettings(const QString& lookupString) {
|
||||
#if defined(USE_GLES) && defined(Q_OS_WIN)
|
||||
|
@ -247,9 +251,12 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_USER, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// in case we're failing to connect to where we thought this user was
|
||||
// store their username as previous lookup so we can refresh their location via API
|
||||
_previousLookup = lookupUrl;
|
||||
_previousAPILookup = lookupUrl;
|
||||
} else {
|
||||
// we're assuming this is either a network address or global place name
|
||||
// check if it is a network address first
|
||||
|
@ -259,8 +266,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_NETWORK_ADDRESS, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// a network address lookup clears the previous lookup since we don't expect to re-attempt it
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
// If the host changed then we have already saved to history
|
||||
if (hostChanged) {
|
||||
|
@ -278,8 +288,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
} else if (handleDomainID(lookupUrl.host())){
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_DOMAIN_ID, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// store this domain ID as the previous lookup in case we're failing to connect and want to refresh API info
|
||||
_previousLookup = lookupUrl;
|
||||
_previousAPILookup = lookupUrl;
|
||||
|
||||
// no place name - this is probably a domain ID
|
||||
// try to look up the domain ID on the metaverse API
|
||||
|
@ -287,8 +300,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
} else {
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_PLACE, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// store this place name as the previous lookup in case we fail to connect and want to refresh API info
|
||||
_previousLookup = lookupUrl;
|
||||
_previousAPILookup = lookupUrl;
|
||||
|
||||
// wasn't an address - lookup the place name
|
||||
// we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after
|
||||
|
@ -302,7 +318,7 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
qCDebug(networking) << "Going to relative path" << lookupUrl.path();
|
||||
|
||||
// a path lookup clears the previous lookup since we don't expect to re-attempt it
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
// if this is a relative path then handle it as a relative viewpoint
|
||||
handlePath(lookupUrl.path(), trigger, true);
|
||||
|
@ -314,7 +330,10 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
// be loaded over http(s)
|
||||
// lookupUrl.scheme() == URL_SCHEME_HTTP ||
|
||||
// lookupUrl.scheme() == URL_SCHEME_HTTPS ||
|
||||
_previousLookup.clear();
|
||||
// TODO once a file can return a connection refusal if there were to be some kind of load error, we'd
|
||||
// need to store the previous domain tried in _lastVisitedURL. For now , do not store it.
|
||||
|
||||
_previousAPILookup.clear();
|
||||
_shareablePlaceName.clear();
|
||||
setDomainInfo(lookupUrl, trigger);
|
||||
emit lookupResultsFinished();
|
||||
|
@ -381,7 +400,7 @@ void AddressManager::handleAPIResponse(QNetworkReply* requestReply) {
|
|||
QJsonObject dataObject = responseObject["data"].toObject();
|
||||
|
||||
// Lookup succeeded, don't keep re-trying it (especially on server restarts)
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
if (!dataObject.isEmpty()) {
|
||||
goToAddressFromObject(dataObject.toVariantMap(), requestReply);
|
||||
|
@ -547,7 +566,7 @@ void AddressManager::handleAPIError(QNetworkReply* errorReply) {
|
|||
|
||||
if (errorReply->error() == QNetworkReply::ContentNotFoundError) {
|
||||
// if this is a lookup that has no result, don't keep re-trying it
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
emit lookupResultIsNotFound();
|
||||
}
|
||||
|
@ -709,7 +728,6 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
|
|||
// We use _newHostLookupPath to determine if the client has already stored its last address
|
||||
// before moving to a new host thanks to the information in the same lookup URL.
|
||||
|
||||
|
||||
if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)
|
||||
|| trigger == Back || trigger == Forward) {
|
||||
addCurrentAddressToHistory(trigger);
|
||||
|
@ -843,8 +861,8 @@ void AddressManager::goToUser(const QString& username, bool shouldMatchOrientati
|
|||
|
||||
void AddressManager::refreshPreviousLookup() {
|
||||
// if we have a non-empty previous lookup, fire it again now (but don't re-store it in the history)
|
||||
if (!_previousLookup.isEmpty()) {
|
||||
handleUrl(_previousLookup, LookupTrigger::AttemptedRefresh);
|
||||
if (!_previousAPILookup.isEmpty()) {
|
||||
handleUrl(_previousAPILookup, LookupTrigger::AttemptedRefresh);
|
||||
} else {
|
||||
handleUrl(currentAddress(), LookupTrigger::AttemptedRefresh);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "AccountManager.h"
|
||||
|
||||
extern const QString DEFAULT_HIFI_ADDRESS;
|
||||
extern const QString REDIRECT_HIFI_ADDRESS;
|
||||
|
||||
const QString SANDBOX_HIFI_ADDRESS = "hifi://localhost";
|
||||
const QString INDEX_PATH = "/";
|
||||
|
@ -55,7 +56,6 @@ const QString GET_PLACE = "/api/v1/places/%1";
|
|||
* <em>Read-only.</em>
|
||||
* @property {boolean} isConnected - <code>true</code> if you're connected to the domain in your current <code>href</code>
|
||||
* metaverse address, otherwise <code>false</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {string} pathname - The location and orientation in your current <code>href</code> metaverse address
|
||||
* (e.g., <code>"/15,-10,26/0,0,0,1"</code>).
|
||||
* <em>Read-only.</em>
|
||||
|
@ -140,7 +140,8 @@ public:
|
|||
* </table>
|
||||
* @typedef {number} location.LookupTrigger
|
||||
*/
|
||||
enum LookupTrigger {
|
||||
enum LookupTrigger
|
||||
{
|
||||
UserInput,
|
||||
Back,
|
||||
Forward,
|
||||
|
@ -164,6 +165,8 @@ public:
|
|||
QString currentPath(bool withOrientation = true) const;
|
||||
QString currentFacingPath() const;
|
||||
|
||||
QUrl lastAddress() const;
|
||||
|
||||
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
||||
QString getPlaceName() const;
|
||||
QString getDomainID() const;
|
||||
|
@ -191,7 +194,7 @@ public slots:
|
|||
* Helps ensure that user's location history is correctly maintained.
|
||||
*/
|
||||
void handleLookupString(const QString& lookupString, bool fromSuggestions = false);
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* Go to a position and orientation resulting from a lookup for a named path in the domain (set in the domain server's
|
||||
* settings).
|
||||
|
@ -204,8 +207,9 @@ public slots:
|
|||
// functions and signals that should be exposed are moved to a scripting interface class.
|
||||
//
|
||||
// we currently expect this to be called from NodeList once handleLookupString has been called with a path
|
||||
bool goToViewpointForPath(const QString& viewpointString, const QString& pathString)
|
||||
{ return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString); }
|
||||
bool goToViewpointForPath(const QString& viewpointString, const QString& pathString) {
|
||||
return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString);
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Go back to the previous location in your navigation history, if there is one.
|
||||
|
@ -226,8 +230,10 @@ public slots:
|
|||
* @param {location.LookupTrigger} trigger=StartupFromSettings - The reason for the function call. Helps ensure that user's
|
||||
* location history is correctly maintained.
|
||||
*/
|
||||
void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger); }
|
||||
|
||||
void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) {
|
||||
handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger);
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Go to the default "welcome" metaverse address.
|
||||
* @function location.goToEntry
|
||||
|
@ -245,6 +251,12 @@ public slots:
|
|||
*/
|
||||
void goToUser(const QString& username, bool shouldMatchOrientation = true);
|
||||
|
||||
/**jsdoc
|
||||
* Go to the last address tried. This will be the last URL tried from location.handleLookupString
|
||||
* @function location.goToLastAddress
|
||||
*/
|
||||
void goToLastAddress() { handleUrl(_lastVisitedURL, LookupTrigger::AttemptedRefresh); }
|
||||
|
||||
/**jsdoc
|
||||
* Refresh the current address, e.g., after connecting to a domain in order to position the user to the desired location.
|
||||
* @function location.refreshPreviousLookup
|
||||
|
@ -352,7 +364,8 @@ signals:
|
|||
* location.locationChangeRequired.connect(onLocationChangeRequired);
|
||||
*/
|
||||
void locationChangeRequired(const glm::vec3& newPosition,
|
||||
bool hasOrientationChange, const glm::quat& newOrientation,
|
||||
bool hasOrientationChange,
|
||||
const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation);
|
||||
|
||||
/**jsdoc
|
||||
|
@ -423,7 +436,7 @@ private slots:
|
|||
void handleShareableNameAPIResponse(QNetworkReply* requestReply);
|
||||
|
||||
private:
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply* reply);
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply* reply);
|
||||
|
||||
// Set host and port, and return `true` if it was changed.
|
||||
bool setHost(const QString& host, LookupTrigger trigger, quint16 port = 0);
|
||||
|
@ -435,8 +448,11 @@ private:
|
|||
|
||||
bool handleNetworkAddress(const QString& lookupString, LookupTrigger trigger, bool& hostChanged);
|
||||
void handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly = false);
|
||||
bool handleViewpoint(const QString& viewpointString, bool shouldFace, LookupTrigger trigger,
|
||||
bool definitelyPathOnly = false, const QString& pathString = QString());
|
||||
bool handleViewpoint(const QString& viewpointString,
|
||||
bool shouldFace,
|
||||
LookupTrigger trigger,
|
||||
bool definitelyPathOnly = false,
|
||||
const QString& pathString = QString());
|
||||
bool handleUsername(const QString& lookupString);
|
||||
bool handleDomainID(const QString& host);
|
||||
|
||||
|
@ -446,6 +462,7 @@ private:
|
|||
void addCurrentAddressToHistory(LookupTrigger trigger);
|
||||
|
||||
QUrl _domainURL;
|
||||
QUrl _lastVisitedURL;
|
||||
|
||||
QUuid _rootPlaceID;
|
||||
PositionGetter _positionGetter;
|
||||
|
@ -459,7 +476,7 @@ private:
|
|||
|
||||
QString _newHostLookupPath;
|
||||
|
||||
QUrl _previousLookup;
|
||||
QUrl _previousAPILookup;
|
||||
};
|
||||
|
||||
#endif // hifi_AddressManager_h
|
||||
#endif // hifi_AddressManager_h
|
||||
|
|
|
@ -99,6 +99,7 @@ void DomainHandler::softReset() {
|
|||
|
||||
clearSettings();
|
||||
|
||||
_isInErrorState = false;
|
||||
_connectionDenialsSinceKeypairRegen = 0;
|
||||
_checkInPacketsSinceLastReply = 0;
|
||||
|
||||
|
@ -128,6 +129,11 @@ void DomainHandler::hardReset() {
|
|||
_pendingPath.clear();
|
||||
}
|
||||
|
||||
void DomainHandler::setErrorDomainURL(const QUrl& url) {
|
||||
_errorDomainURL = url;
|
||||
return;
|
||||
}
|
||||
|
||||
void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hostname) {
|
||||
if (_sockAddr != sockAddr) {
|
||||
// we should reset on a sockAddr change
|
||||
|
@ -171,7 +177,8 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) {
|
|||
domainPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
}
|
||||
|
||||
if (_domainURL != domainURL || _sockAddr.getPort() != domainPort) {
|
||||
// if it's in the error state, reset and try again.
|
||||
if ((_domainURL != domainURL || _sockAddr.getPort() != domainPort) || _isInErrorState) {
|
||||
// re-set the domain info so that auth information is reloaded
|
||||
hardReset();
|
||||
|
||||
|
@ -206,7 +213,8 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) {
|
|||
|
||||
void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id) {
|
||||
|
||||
if (_iceServerSockAddr.getAddress().toString() != iceServerHostname || id != _pendingDomainID) {
|
||||
// if it's in the error state, reset and try again.
|
||||
if ((_iceServerSockAddr.getAddress().toString() != iceServerHostname || id != _pendingDomainID) || _isInErrorState) {
|
||||
// re-set the domain info to connect to new domain
|
||||
hardReset();
|
||||
|
||||
|
@ -316,6 +324,23 @@ void DomainHandler::connectedToServerless(std::map<QString, QString> namedPaths)
|
|||
setIsConnected(true);
|
||||
}
|
||||
|
||||
void DomainHandler::loadedErrorDomain(std::map<QString, QString> namedPaths) {
|
||||
auto lookup = namedPaths.find("/");
|
||||
QString viewpoint;
|
||||
if (lookup != namedPaths.end()) {
|
||||
viewpoint = lookup->second;
|
||||
} else {
|
||||
viewpoint = DOMAIN_SPAWNING_POINT;
|
||||
}
|
||||
DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, QString());
|
||||
}
|
||||
|
||||
void DomainHandler::setRedirectErrorState(QUrl errorUrl, int reasonCode) {
|
||||
_errorDomainURL = errorUrl;
|
||||
_lastDomainConnectionError = reasonCode;
|
||||
emit redirectToErrorDomainURL(_errorDomainURL);
|
||||
}
|
||||
|
||||
void DomainHandler::requestDomainSettings() {
|
||||
qCDebug(networking) << "Requesting settings from domain server";
|
||||
|
||||
|
@ -451,7 +476,18 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
|
|||
|
||||
if (!_domainConnectionRefusals.contains(reasonMessage)) {
|
||||
_domainConnectionRefusals.insert(reasonMessage);
|
||||
#if defined(Q_OS_ANDROID)
|
||||
emit domainConnectionRefused(reasonMessage, (int)reasonCode, extraInfo);
|
||||
#else
|
||||
if (reasonCode == ConnectionRefusedReason::ProtocolMismatch || reasonCode == ConnectionRefusedReason::NotAuthorized) {
|
||||
_isInErrorState = true;
|
||||
// ingest the error - this is a "hard" connection refusal.
|
||||
emit redirectToErrorDomainURL(_errorDomainURL);
|
||||
} else {
|
||||
emit domainConnectionRefused(reasonMessage, (int)reasonCode, extraInfo);
|
||||
}
|
||||
_lastDomainConnectionError = (int)reasonCode;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
|
|
@ -50,6 +50,11 @@ public:
|
|||
|
||||
QString getHostname() const { return _domainURL.host(); }
|
||||
|
||||
QUrl getErrorDomainURL(){ return _errorDomainURL; }
|
||||
void setErrorDomainURL(const QUrl& url);
|
||||
|
||||
int getLastDomainConnectionError() { return _lastDomainConnectionError; }
|
||||
|
||||
const QHostAddress& getIP() const { return _sockAddr.getAddress(); }
|
||||
void setIPToLocalhost() { _sockAddr.setAddress(QHostAddress(QHostAddress::LocalHost)); }
|
||||
|
||||
|
@ -81,6 +86,10 @@ public:
|
|||
|
||||
void connectedToServerless(std::map<QString, QString> namedPaths);
|
||||
|
||||
void loadedErrorDomain(std::map<QString, QString> namedPaths);
|
||||
// sets domain handler in error state.
|
||||
void setRedirectErrorState(QUrl errorUrl, int reasonCode);
|
||||
|
||||
QString getViewPointFromNamedPath(QString namedPath);
|
||||
|
||||
bool hasSettings() const { return !_settingsObject.isEmpty(); }
|
||||
|
@ -135,6 +144,11 @@ public:
|
|||
* <td><code>4</code></td>
|
||||
* <td>The domain already has its maximum number of users.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><strong>TimedOut</strong></td>
|
||||
* <td><code>5</code></td>
|
||||
* <td>Connecting to the domain timed out.</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {number} Window.ConnectionRefusedReason
|
||||
|
@ -144,7 +158,8 @@ public:
|
|||
ProtocolMismatch,
|
||||
LoginError,
|
||||
NotAuthorized,
|
||||
TooManyUsers
|
||||
TooManyUsers,
|
||||
TimedOut
|
||||
};
|
||||
|
||||
public slots:
|
||||
|
@ -164,6 +179,8 @@ private slots:
|
|||
signals:
|
||||
void domainURLChanged(QUrl domainURL);
|
||||
|
||||
void domainConnectionErrorChanged(int reasonCode);
|
||||
|
||||
// NOTE: the emission of completedSocketDiscovery does not mean a connection to DS is established
|
||||
// It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on
|
||||
void completedSocketDiscovery();
|
||||
|
@ -179,6 +196,7 @@ signals:
|
|||
void settingsReceiveFail();
|
||||
|
||||
void domainConnectionRefused(QString reasonMessage, int reason, const QString& extraInfo);
|
||||
void redirectToErrorDomainURL(QUrl errorDomainURL);
|
||||
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
|
||||
|
@ -190,6 +208,7 @@ private:
|
|||
QUuid _uuid;
|
||||
Node::LocalID _localID;
|
||||
QUrl _domainURL;
|
||||
QUrl _errorDomainURL;
|
||||
HifiSockAddr _sockAddr;
|
||||
QUuid _assignmentUUID;
|
||||
QUuid _connectionToken;
|
||||
|
@ -198,6 +217,7 @@ private:
|
|||
HifiSockAddr _iceServerSockAddr;
|
||||
NetworkPeer _icePeer;
|
||||
bool _isConnected { false };
|
||||
bool _isInErrorState { false };
|
||||
QJsonObject _settingsObject;
|
||||
QString _pendingPath;
|
||||
QTimer _settingsTimer;
|
||||
|
@ -210,6 +230,9 @@ private:
|
|||
QTimer _apiRefreshTimer;
|
||||
|
||||
std::map<QString, QString> _namedPaths;
|
||||
|
||||
// domain connection error upon connection refusal.
|
||||
int _lastDomainConnectionError{ -1 };
|
||||
};
|
||||
|
||||
const QString DOMAIN_SPAWNING_POINT { "/0, -10, 0" };
|
||||
|
|
|
@ -38,10 +38,10 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
|
|||
if (_disabled.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
|
||||
// Adding the action name
|
||||
QHttpPart actionPart;
|
||||
actionPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"action_name\"");
|
||||
|
@ -53,7 +53,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
|
|||
elapsedPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"elapsed_ms\"");
|
||||
elapsedPart.setBody(QString::number(_timer.elapsed()).toLocal8Bit());
|
||||
multipart->append(elapsedPart);
|
||||
|
||||
|
||||
// If there are action details, add them to the multipart
|
||||
if (!details.isEmpty()) {
|
||||
QHttpPart detailsPart;
|
||||
|
@ -62,13 +62,13 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
|
|||
detailsPart.setBody(QJsonDocument(details).toJson(QJsonDocument::Compact));
|
||||
multipart->append(detailsPart);
|
||||
}
|
||||
|
||||
|
||||
// if no callbacks specified, call our owns
|
||||
if (params.isEmpty()) {
|
||||
params.callbackReceiver = this;
|
||||
params.errorCallbackMethod = "requestError";
|
||||
}
|
||||
|
||||
|
||||
accountManager->sendRequest(USER_ACTIVITY_URL,
|
||||
AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
|
@ -88,7 +88,7 @@ void UserActivityLogger::launch(QString applicationVersion, bool previousSession
|
|||
actionDetails.insert(VERSION_KEY, applicationVersion);
|
||||
actionDetails.insert(CRASH_KEY, previousSessionCrashed);
|
||||
actionDetails.insert(RUNTIME_KEY, previousSessionRuntime);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
}
|
||||
|
||||
|
@ -105,9 +105,9 @@ void UserActivityLogger::changedDisplayName(QString displayName) {
|
|||
const QString ACTION_NAME = "changed_display_name";
|
||||
QJsonObject actionDetails;
|
||||
const QString DISPLAY_NAME = "display_name";
|
||||
|
||||
|
||||
actionDetails.insert(DISPLAY_NAME, displayName);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
}
|
||||
|
||||
|
@ -116,10 +116,10 @@ void UserActivityLogger::changedModel(QString typeOfModel, QString modelURL) {
|
|||
QJsonObject actionDetails;
|
||||
const QString TYPE_OF_MODEL = "type_of_model";
|
||||
const QString MODEL_URL = "model_url";
|
||||
|
||||
|
||||
actionDetails.insert(TYPE_OF_MODEL, typeOfModel);
|
||||
actionDetails.insert(MODEL_URL, modelURL);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
}
|
||||
|
||||
|
@ -127,9 +127,9 @@ void UserActivityLogger::changedDomain(QString domainURL) {
|
|||
const QString ACTION_NAME = "changed_domain";
|
||||
QJsonObject actionDetails;
|
||||
const QString DOMAIN_URL = "domain_url";
|
||||
|
||||
|
||||
actionDetails.insert(DOMAIN_URL, domainURL);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
}
|
||||
|
||||
|
@ -151,10 +151,10 @@ void UserActivityLogger::connectedDevice(QString typeOfDevice, QString deviceNam
|
|||
QJsonObject actionDetails;
|
||||
const QString TYPE_OF_DEVICE = "type_of_device";
|
||||
const QString DEVICE_NAME = "device_name";
|
||||
|
||||
|
||||
actionDetails.insert(TYPE_OF_DEVICE, typeOfDevice);
|
||||
actionDetails.insert(DEVICE_NAME, deviceName);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
|
||||
}
|
||||
|
@ -163,9 +163,9 @@ void UserActivityLogger::loadedScript(QString scriptName) {
|
|||
const QString ACTION_NAME = "loaded_script";
|
||||
QJsonObject actionDetails;
|
||||
const QString SCRIPT_NAME = "script_name";
|
||||
|
||||
|
||||
actionDetails.insert(SCRIPT_NAME, scriptName);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
|
||||
}
|
||||
|
@ -199,10 +199,10 @@ void UserActivityLogger::wentTo(AddressManager::LookupTrigger lookupTrigger, QSt
|
|||
const QString TRIGGER_TYPE_KEY = "trigger";
|
||||
const QString DESTINATION_TYPE_KEY = "destination_type";
|
||||
const QString DESTINATION_NAME_KEY = "detination_name";
|
||||
|
||||
|
||||
actionDetails.insert(TRIGGER_TYPE_KEY, trigger);
|
||||
actionDetails.insert(DESTINATION_TYPE_KEY, destinationType);
|
||||
actionDetails.insert(DESTINATION_NAME_KEY, destinationName);
|
||||
|
||||
|
||||
logAction(ACTION_NAME, actionDetails);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
];
|
||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||
"system/controllers/controllerScripts.js",
|
||||
"system/interstitialPage.js"
|
||||
//"system/chat.js"
|
||||
];
|
||||
|
||||
|
|
476
scripts/system/interstitialPage.js
Normal file
|
@ -0,0 +1,476 @@
|
|||
//
|
||||
// interstitialPage.js
|
||||
// scripts/system
|
||||
//
|
||||
// Created by Dante Ruiz on 08/02/2018.
|
||||
// Copyright 2012 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
|
||||
//
|
||||
|
||||
/* global Script, Controller, Overlays, Quat, MyAvatar, Entities, print, Vec3, AddressManager, Render, Window, Toolbars,
|
||||
Camera, HMD, location, Account, Xform*/
|
||||
|
||||
(function() {
|
||||
Script.include("/~/system/libraries/Xform.js");
|
||||
var DEBUG = false;
|
||||
var MIN_LOADING_PROGRESS = 3.6;
|
||||
var TOTAL_LOADING_PROGRESS = 3.8;
|
||||
var EPSILON = 0.01;
|
||||
var isVisible = false;
|
||||
var VOLUME = 0.4;
|
||||
var tune = SoundCache.getSound("http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/crystals_and_voices.wav");
|
||||
var sample = null;
|
||||
var MAX_LEFT_MARGIN = 1.9;
|
||||
var INNER_CIRCLE_WIDTH = 4.7;
|
||||
var DEFAULT_Z_OFFSET = 5.45;
|
||||
var previousCameraMode = Camera.mode;
|
||||
|
||||
var renderViewTask = Render.getConfig("RenderMainView");
|
||||
var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
var request = Script.require('request').request;
|
||||
var BUTTON_PROPERTIES = {
|
||||
text: "Interstitial"
|
||||
};
|
||||
|
||||
var tablet = null;
|
||||
var button = null;
|
||||
|
||||
// Tips have a character limit of 69
|
||||
var userTips = [
|
||||
"Tip: Visit TheSpot to explore featured domains!",
|
||||
"Tip: Visit our docs online to learn more about scripting!",
|
||||
"Tip: Don't want others invading your personal space? Turn on the Bubble!",
|
||||
"Tip: Want to make a friend? Shake hands with them in VR!",
|
||||
"Tip: Enjoy live music? Visit Rust to dance your heart out!",
|
||||
"Tip: Have you visited BodyMart to check out the new avatars recently?",
|
||||
"Tip: Use the Create app to import models and create custom entities.",
|
||||
"Tip: We're open source! Feel free to contribute to our code on GitHub!",
|
||||
"Tip: What emotes have you used in the Emote app?",
|
||||
"Tip: Take and share your snapshots with the everyone using the Snap app.",
|
||||
"Tip: Did you know you can show websites in-world by creating a web entity?",
|
||||
"Tip: Find out more information about domains by visiting our website!",
|
||||
"Tip: Did you know you can get cool new apps from the Marketplace?",
|
||||
"Tip: Print your snapshots from the Snap app to share with others!",
|
||||
"Tip: Log in to make friends, visit new domains, and save avatars!"
|
||||
];
|
||||
|
||||
var DEFAULT_DIMENSIONS = { x: 24, y: 24, z: 24 };
|
||||
|
||||
var loadingSphereID = Overlays.addOverlay("model", {
|
||||
name: "Loading-Sphere",
|
||||
position: Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0.0, y: -1.0, z: 0.0}), Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.95, z: 0})),
|
||||
orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation),
|
||||
url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/black-sphere.fbx",
|
||||
dimensions: DEFAULT_DIMENSIONS,
|
||||
alpha: 1,
|
||||
visible: isVisible,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
parentID: MyAvatar.SELF_ID
|
||||
});
|
||||
|
||||
var anchorOverlay = Overlays.addOverlay("cube", {
|
||||
dimensions: {x: 0.2, y: 0.2, z: 0.2},
|
||||
visible: false,
|
||||
grabbable: false,
|
||||
ignoreRayIntersection: true,
|
||||
localPosition: {x: 0.0, y: getAnchorLocalYOffset(), z: DEFAULT_Z_OFFSET },
|
||||
orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation),
|
||||
solid: true,
|
||||
drawInFront: true,
|
||||
parentID: loadingSphereID
|
||||
});
|
||||
|
||||
|
||||
var domainName = "";
|
||||
var domainNameTextID = Overlays.addOverlay("text3d", {
|
||||
name: "Loading-Destination-Card-Text",
|
||||
localPosition: { x: 0.0, y: 0.8, z: -0.001 },
|
||||
text: domainName,
|
||||
textAlpha: 1,
|
||||
backgroundAlpha: 1,
|
||||
lineHeight: 0.42,
|
||||
visible: isVisible,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var domainText = "";
|
||||
var domainDescription = Overlays.addOverlay("text3d", {
|
||||
name: "Loading-Hostname",
|
||||
localPosition: { x: 0.0, y: 0.32, z: 0.0 },
|
||||
text: domainText,
|
||||
textAlpha: 1,
|
||||
backgroundAlpha: 1,
|
||||
lineHeight: 0.13,
|
||||
visible: isVisible,
|
||||
backgroundAlpha: 0,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var toolTip = "";
|
||||
|
||||
var domainToolTip = Overlays.addOverlay("text3d", {
|
||||
name: "Loading-Tooltip",
|
||||
localPosition: { x: 0.0 , y: -1.6, z: 0.0 },
|
||||
text: toolTip,
|
||||
textAlpha: 1,
|
||||
backgroundAlpha: 1,
|
||||
lineHeight: 0.13,
|
||||
visible: isVisible,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var loadingToTheSpotID = Overlays.addOverlay("image3d", {
|
||||
name: "Loading-Destination-Card-Text",
|
||||
localPosition: { x: 0.0 , y: -1.8, z: 0.0 },
|
||||
url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/goTo_button.png",
|
||||
alpha: 1,
|
||||
dimensions: { x: 1.2, y: 0.6},
|
||||
visible: isVisible,
|
||||
emissive: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var loadingBarPlacard = Overlays.addOverlay("image3d", {
|
||||
name: "Loading-Bar-Placard",
|
||||
localPosition: { x: 0.0, y: -0.99, z: 0.3 },
|
||||
url: Script.resourcesPath() + "images/loadingBar_placard.png",
|
||||
alpha: 1,
|
||||
dimensions: { x: 4, y: 2.8},
|
||||
visible: isVisible,
|
||||
emissive: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var loadingBarProgress = Overlays.addOverlay("image3d", {
|
||||
name: "Loading-Bar-Progress",
|
||||
localPosition: { x: 0.0, y: -0.90, z: 0.0 },
|
||||
url: Script.resourcesPath() + "images/loadingBar_progress.png",
|
||||
alpha: 1,
|
||||
dimensions: {x: 3.8, y: 2.8},
|
||||
visible: isVisible,
|
||||
emissive: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update
|
||||
var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ;
|
||||
var lastInterval = Date.now();
|
||||
var currentDomain = "no domain";
|
||||
var timer = null;
|
||||
var target = 0;
|
||||
|
||||
var connectionToDomainFailed = false;
|
||||
|
||||
|
||||
function getAnchorLocalYOffset() {
|
||||
var loadingSpherePosition = Overlays.getProperty(loadingSphereID, "position");
|
||||
var loadingSphereOrientation = Overlays.getProperty(loadingSphereID, "rotation");
|
||||
var overlayXform = new Xform(loadingSphereOrientation, loadingSpherePosition);
|
||||
var worldToOverlayXform = overlayXform.inv();
|
||||
var headPosition = MyAvatar.getHeadPosition();
|
||||
var headPositionInOverlaySpace = worldToOverlayXform.xformPoint(headPosition);
|
||||
return headPositionInOverlaySpace.y;
|
||||
}
|
||||
|
||||
function getLeftMargin(overlayID, text) {
|
||||
var textSize = Overlays.textSize(overlayID, text);
|
||||
var sizeDifference = ((INNER_CIRCLE_WIDTH - textSize.width) / 2);
|
||||
var leftMargin = -(MAX_LEFT_MARGIN - sizeDifference);
|
||||
return leftMargin;
|
||||
}
|
||||
|
||||
function lerp(a, b, t) {
|
||||
return ((1 - t) * a + t * b);
|
||||
}
|
||||
|
||||
function resetValues() {
|
||||
var properties = {
|
||||
localPosition: { x: 1.85, y: -0.935, z: 0.0 },
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 2.8
|
||||
}
|
||||
};
|
||||
|
||||
Overlays.editOverlay(loadingBarProgress, properties);
|
||||
}
|
||||
|
||||
function startInterstitialPage() {
|
||||
if (timer === null) {
|
||||
updateOverlays(false);
|
||||
startAudio();
|
||||
target = 0;
|
||||
currentProgress = 0.1;
|
||||
connectionToDomainFailed = false;
|
||||
previousCameraMode = Camera.mode;
|
||||
Camera.mode = "first person";
|
||||
timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
|
||||
function startAudio() {
|
||||
sample = Audio.playSound(tune, {
|
||||
localOnly: true,
|
||||
position: MyAvatar.getHeadPosition(),
|
||||
volume: VOLUME
|
||||
});
|
||||
}
|
||||
|
||||
function endAudio() {
|
||||
sample.stop();
|
||||
sample = null;
|
||||
}
|
||||
|
||||
function domainChanged(domain) {
|
||||
if (domain !== currentDomain) {
|
||||
MyAvatar.restoreAnimation();
|
||||
var name = location.placename;
|
||||
domainName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
var doRequest = true;
|
||||
if (name.length === 0 && location.href === "file:///~/serverless/tutorial.json") {
|
||||
domainName = "Serveless Domain (Tutorial)";
|
||||
doRequest = false;
|
||||
}
|
||||
var domainNameLeftMargin = getLeftMargin(domainNameTextID, domainName);
|
||||
var textProperties = {
|
||||
text: domainName,
|
||||
leftMargin: domainNameLeftMargin
|
||||
};
|
||||
|
||||
if (doRequest) {
|
||||
var url = Account.metaverseServerURL + '/api/v1/places/' + domain;
|
||||
request({
|
||||
uri: url
|
||||
}, function(error, data) {
|
||||
if (data.status === "success") {
|
||||
var domainInfo = data.data;
|
||||
var domainDescriptionText = domainInfo.place.description;
|
||||
var leftMargin = getLeftMargin(domainDescription, domainDescriptionText);
|
||||
var domainDescriptionProperties = {
|
||||
text: domainDescriptionText,
|
||||
leftMargin: leftMargin
|
||||
};
|
||||
Overlays.editOverlay(domainDescription, domainDescriptionProperties);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var domainDescriptionProperties = {
|
||||
text: ""
|
||||
};
|
||||
Overlays.editOverlay(domainDescription, domainDescriptionProperties);
|
||||
}
|
||||
|
||||
var randomIndex = Math.floor(Math.random() * userTips.length);
|
||||
var tip = userTips[randomIndex];
|
||||
var tipLeftMargin = getLeftMargin(domainToolTip, tip);
|
||||
var toolTipProperties = {
|
||||
text: tip,
|
||||
leftMargin: tipLeftMargin
|
||||
};
|
||||
|
||||
Overlays.editOverlay(domainNameTextID, textProperties);
|
||||
Overlays.editOverlay(domainToolTip, toolTipProperties);
|
||||
|
||||
|
||||
startInterstitialPage();
|
||||
currentDomain = domain;
|
||||
}
|
||||
}
|
||||
|
||||
var THE_PLACE = (HifiAbout.buildVersion === "dev") ? "hifi://TheSpot-dev": "hifi://TheSpot";
|
||||
function clickedOnOverlay(overlayID, event) {
|
||||
if (loadingToTheSpotID === overlayID) {
|
||||
location.handleLookupString(THE_PLACE);
|
||||
}
|
||||
}
|
||||
|
||||
var currentProgress = 0.1;
|
||||
|
||||
function updateOverlays(physicsEnabled) {
|
||||
var properties = {
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
var mainSphereProperties = {
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
var domainTextProperties = {
|
||||
text: domainText,
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
var loadingBarProperties = {
|
||||
dimensions: { x: 0.0, y: 2.8 },
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
if (!HMD.active) {
|
||||
MyAvatar.headOrientation = Quat.multiply(Quat.cancelOutRollAndPitch(MyAvatar.headOrientation), Quat.fromPitchYawRollDegrees(-3.0, 0, 0));
|
||||
}
|
||||
|
||||
renderViewTask.getConfig("LightingModel")["enableAmbientLight"] = physicsEnabled;
|
||||
renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = physicsEnabled;
|
||||
renderViewTask.getConfig("LightingModel")["enablePointLight"] = physicsEnabled;
|
||||
Overlays.editOverlay(loadingSphereID, mainSphereProperties);
|
||||
Overlays.editOverlay(loadingToTheSpotID, properties);
|
||||
Overlays.editOverlay(domainNameTextID, properties);
|
||||
Overlays.editOverlay(domainDescription, domainTextProperties);
|
||||
Overlays.editOverlay(domainToolTip, properties);
|
||||
Overlays.editOverlay(loadingBarPlacard, properties);
|
||||
Overlays.editOverlay(loadingBarProgress, loadingBarProperties);
|
||||
|
||||
|
||||
Menu.setIsOptionChecked("Show Overlays", physicsEnabled);
|
||||
if (!HMD.active) {
|
||||
toolbar.writeProperty("visible", physicsEnabled);
|
||||
}
|
||||
|
||||
resetValues();
|
||||
|
||||
if (physicsEnabled) {
|
||||
Camera.mode = previousCameraMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function scaleInterstitialPage(sensorToWorldScale) {
|
||||
var yOffset = getAnchorLocalYOffset();
|
||||
var localPosition = {
|
||||
x: 0.0,
|
||||
y: yOffset,
|
||||
z: 5.45
|
||||
};
|
||||
|
||||
Overlays.editOverlay(anchorOverlay, { localPosition: localPosition });
|
||||
}
|
||||
|
||||
function update() {
|
||||
var physicsEnabled = Window.isPhysicsEnabled();
|
||||
var thisInterval = Date.now();
|
||||
var deltaTime = (thisInterval - lastInterval);
|
||||
lastInterval = thisInterval;
|
||||
|
||||
var domainLoadingProgressPercentage = Window.domainLoadingProgress();
|
||||
|
||||
var progress = MIN_LOADING_PROGRESS * domainLoadingProgressPercentage;
|
||||
if (progress >= target) {
|
||||
target = progress;
|
||||
}
|
||||
|
||||
if ((physicsEnabled && (currentProgress < TOTAL_LOADING_PROGRESS))) {
|
||||
target = TOTAL_LOADING_PROGRESS;
|
||||
}
|
||||
|
||||
currentProgress = lerp(currentProgress, target, 0.2);
|
||||
var properties = {
|
||||
localPosition: { x: (1.85 - (currentProgress / 2) - (-0.029 * (currentProgress / TOTAL_LOADING_PROGRESS))), y: -0.935, z: 0.0 },
|
||||
dimensions: {
|
||||
x: currentProgress,
|
||||
y: 2.8
|
||||
}
|
||||
};
|
||||
|
||||
Overlays.editOverlay(loadingBarProgress, properties);
|
||||
if ((physicsEnabled && (currentProgress >= (TOTAL_LOADING_PROGRESS - EPSILON)))) {
|
||||
updateOverlays((physicsEnabled || connectionToDomainFailed));
|
||||
endAudio();
|
||||
currentDomain = "no domain";
|
||||
timer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS);
|
||||
}
|
||||
var whiteColor = {red: 255, green: 255, blue: 255};
|
||||
var greyColor = {red: 125, green: 125, blue: 125};
|
||||
Overlays.mouseReleaseOnOverlay.connect(clickedOnOverlay);
|
||||
Overlays.hoverEnterOverlay.connect(function(overlayID, event) {
|
||||
if (overlayID === loadingToTheSpotID) {
|
||||
Overlays.editOverlay(loadingToTheSpotID, { color: greyColor});
|
||||
}
|
||||
});
|
||||
|
||||
Overlays.hoverLeaveOverlay.connect(function(overlayID, event) {
|
||||
if (overlayID === loadingToTheSpotID) {
|
||||
Overlays.editOverlay(loadingToTheSpotID, { color: whiteColor});
|
||||
}
|
||||
});
|
||||
|
||||
location.hostChanged.connect(domainChanged);
|
||||
location.lookupResultsFinished.connect(function() {
|
||||
Script.setTimeout(function() {
|
||||
connectionToDomainFailed = !location.isConnected;
|
||||
}, 1200);
|
||||
});
|
||||
|
||||
MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage);
|
||||
MyAvatar.sessionUUIDChanged.connect(function() {
|
||||
var avatarSessionUUID = MyAvatar.sessionUUID;
|
||||
Overlays.editOverlay(loadingSphereID, { parentID: avatarSessionUUID });
|
||||
});
|
||||
|
||||
var toggle = true;
|
||||
if (DEBUG) {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton(BUTTON_PROPERTIES);
|
||||
|
||||
button.clicked.connect(function() {
|
||||
toggle = !toggle;
|
||||
updateOverlays(toggle);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Overlays.deleteOverlay(loadingSphereID);
|
||||
Overlays.deleteOverlay(loadingToTheSpotID);
|
||||
Overlays.deleteOverlay(domainNameTextID);
|
||||
Overlays.deleteOverlay(domainDescription);
|
||||
Overlays.deleteOverlay(domainToolTip);
|
||||
Overlays.deleteOverlay(loadingBarPlacard);
|
||||
Overlays.deleteOverlay(loadingBarProgress);
|
||||
Overlays.deleteOverlay(anchorOverlay);
|
||||
|
||||
if (DEBUG) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
|
||||
renderViewTask.getConfig("LightingModel")["enableAmbientLight"] = true;
|
||||
renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = true;
|
||||
renderViewTask.getConfig("LightingModel")["enablePointLight"] = true;
|
||||
Menu.setIsOptionChecked("Show Overlays", true);
|
||||
if (!HMD.active) {
|
||||
toolbar.writeProperty("visible", true);
|
||||
}
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}());
|
|
@ -410,7 +410,7 @@ SelectionDisplay = (function() {
|
|||
var COLOR_RED = { red: 226, green: 51, blue: 77 };
|
||||
var COLOR_HOVER = { red: 227, green: 227, blue: 227 };
|
||||
var COLOR_ROTATE_CURRENT_RING = { red: 255, green: 99, blue: 9 };
|
||||
var COLOR_SCALE_EDGE = { red: 87, green: 87, blue: 87 };
|
||||
var COLOR_BOUNDING_EDGE = { red: 87, green: 87, blue: 87 };
|
||||
var COLOR_SCALE_CUBE = { red: 106, green: 106, blue: 106 };
|
||||
var COLOR_SCALE_CUBE_SELECTED = { red: 18, green: 18, blue: 18 };
|
||||
|
||||
|
@ -433,15 +433,15 @@ SelectionDisplay = (function() {
|
|||
var ROTATE_DISPLAY_SIZE_Y_MULTIPLIER = 0.09;
|
||||
var ROTATE_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.07;
|
||||
|
||||
var STRETCH_SPHERE_OFFSET = 0.06;
|
||||
var STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE = 0.01;
|
||||
var STRETCH_CUBE_OFFSET = 0.06;
|
||||
var STRETCH_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.02;
|
||||
var STRETCH_MINIMUM_DIMENSION = 0.001;
|
||||
var STRETCH_ALL_MINIMUM_DIMENSION = 0.01;
|
||||
var STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE = 6;
|
||||
var STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE = 2;
|
||||
var STRETCH_PANEL_WIDTH = 0.01;
|
||||
|
||||
var SCALE_CUBE_OFFSET = 0.5;
|
||||
var SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.0125;
|
||||
var BOUNDING_EDGE_OFFSET = 0.5;
|
||||
var SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.02;
|
||||
|
||||
var CLONER_OFFSET = { x: 0.9, y: -0.9, z: 0.9 };
|
||||
|
||||
|
@ -495,6 +495,8 @@ SelectionDisplay = (function() {
|
|||
var worldRotationX;
|
||||
var worldRotationY;
|
||||
var worldRotationZ;
|
||||
|
||||
var activeStretchCubePanelOffset = null;
|
||||
|
||||
var previousHandle = null;
|
||||
var previousHandleHelper = null;
|
||||
|
@ -589,20 +591,18 @@ SelectionDisplay = (function() {
|
|||
leftMargin: 0
|
||||
});
|
||||
|
||||
var handlePropertiesStretchSpheres = {
|
||||
alpha: 1,
|
||||
shape: "Sphere",
|
||||
var handlePropertiesStretchCubes = {
|
||||
solid: true,
|
||||
visible: false,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true
|
||||
};
|
||||
var handleStretchXSphere = Overlays.addOverlay("shape", handlePropertiesStretchSpheres);
|
||||
Overlays.editOverlay(handleStretchXSphere, { color: COLOR_RED });
|
||||
var handleStretchYSphere = Overlays.addOverlay("shape", handlePropertiesStretchSpheres);
|
||||
Overlays.editOverlay(handleStretchYSphere, { color: COLOR_GREEN });
|
||||
var handleStretchZSphere = Overlays.addOverlay("shape", handlePropertiesStretchSpheres);
|
||||
Overlays.editOverlay(handleStretchZSphere, { color: COLOR_BLUE });
|
||||
var handleStretchXCube = Overlays.addOverlay("cube", handlePropertiesStretchCubes);
|
||||
Overlays.editOverlay(handleStretchXCube, { color: COLOR_RED });
|
||||
var handleStretchYCube = Overlays.addOverlay("cube", handlePropertiesStretchCubes);
|
||||
Overlays.editOverlay(handleStretchYCube, { color: COLOR_GREEN });
|
||||
var handleStretchZCube = Overlays.addOverlay("cube", handlePropertiesStretchCubes);
|
||||
Overlays.editOverlay(handleStretchZCube, { color: COLOR_BLUE });
|
||||
|
||||
var handlePropertiesStretchPanel = {
|
||||
shape: "Quad",
|
||||
|
@ -619,8 +619,7 @@ SelectionDisplay = (function() {
|
|||
var handleStretchZPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel);
|
||||
Overlays.editOverlay(handleStretchZPanel, { color: COLOR_BLUE });
|
||||
|
||||
var handlePropertiesScaleCubes = {
|
||||
alpha: 1,
|
||||
var handleScaleCube = Overlays.addOverlay("cube", {
|
||||
size: 0.025,
|
||||
color: COLOR_SCALE_CUBE,
|
||||
solid: true,
|
||||
|
@ -628,36 +627,28 @@ SelectionDisplay = (function() {
|
|||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
borderSize: 1.4
|
||||
};
|
||||
var handleScaleLBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, -z)
|
||||
var handleScaleRBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, -z)
|
||||
var handleScaleLBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, z)
|
||||
var handleScaleRBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, z)
|
||||
var handleScaleLTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, -z)
|
||||
var handleScaleRTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, -z)
|
||||
var handleScaleLTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, z)
|
||||
var handleScaleRTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, z)
|
||||
});
|
||||
|
||||
var handlePropertiesScaleEdge = {
|
||||
var handlePropertiesBoundingEdge = {
|
||||
alpha: 1,
|
||||
color: COLOR_SCALE_EDGE,
|
||||
color: COLOR_BOUNDING_EDGE,
|
||||
visible: false,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
lineWidth: 0.2
|
||||
};
|
||||
var handleScaleTREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleTLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleTFEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleTNEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleBREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleBLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleBFEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleBNEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleNREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleNLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleFREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleScaleFLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
var handleBoundingTREdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingTLEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingTFEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingTNEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingBREdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingBLEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingBFEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingBNEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingNREdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingNLEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingFREdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
var handleBoundingFLEdge = Overlays.addOverlay("line3d", handlePropertiesBoundingEdge);
|
||||
|
||||
var handleCloner = Overlays.addOverlay("cube", {
|
||||
alpha: 1,
|
||||
|
@ -738,32 +729,25 @@ SelectionDisplay = (function() {
|
|||
handleRotateRollRing,
|
||||
handleRotateCurrentRing,
|
||||
rotationDegreesDisplay,
|
||||
handleStretchXSphere,
|
||||
handleStretchYSphere,
|
||||
handleStretchZSphere,
|
||||
handleStretchXCube,
|
||||
handleStretchYCube,
|
||||
handleStretchZCube,
|
||||
handleStretchXPanel,
|
||||
handleStretchYPanel,
|
||||
handleStretchZPanel,
|
||||
handleScaleLBNCube,
|
||||
handleScaleRBNCube,
|
||||
handleScaleLBFCube,
|
||||
handleScaleRBFCube,
|
||||
handleScaleLTNCube,
|
||||
handleScaleRTNCube,
|
||||
handleScaleLTFCube,
|
||||
handleScaleRTFCube,
|
||||
handleScaleTREdge,
|
||||
handleScaleTLEdge,
|
||||
handleScaleTFEdge,
|
||||
handleScaleTNEdge,
|
||||
handleScaleBREdge,
|
||||
handleScaleBLEdge,
|
||||
handleScaleBFEdge,
|
||||
handleScaleBNEdge,
|
||||
handleScaleNREdge,
|
||||
handleScaleNLEdge,
|
||||
handleScaleFREdge,
|
||||
handleScaleFLEdge,
|
||||
handleScaleCube,
|
||||
handleBoundingTREdge,
|
||||
handleBoundingTLEdge,
|
||||
handleBoundingTFEdge,
|
||||
handleBoundingTNEdge,
|
||||
handleBoundingBREdge,
|
||||
handleBoundingBLEdge,
|
||||
handleBoundingBFEdge,
|
||||
handleBoundingBNEdge,
|
||||
handleBoundingNREdge,
|
||||
handleBoundingNLEdge,
|
||||
handleBoundingFREdge,
|
||||
handleBoundingFLEdge,
|
||||
handleCloner,
|
||||
selectionBox,
|
||||
iconSelectionBox,
|
||||
|
@ -787,34 +771,27 @@ SelectionDisplay = (function() {
|
|||
overlayNames[handleRotateCurrentRing] = "handleRotateCurrentRing";
|
||||
overlayNames[rotationDegreesDisplay] = "rotationDegreesDisplay";
|
||||
|
||||
overlayNames[handleStretchXSphere] = "handleStretchXSphere";
|
||||
overlayNames[handleStretchYSphere] = "handleStretchYSphere";
|
||||
overlayNames[handleStretchZSphere] = "handleStretchZSphere";
|
||||
overlayNames[handleStretchXCube] = "handleStretchXCube";
|
||||
overlayNames[handleStretchYCube] = "handleStretchYCube";
|
||||
overlayNames[handleStretchZCube] = "handleStretchZCube";
|
||||
overlayNames[handleStretchXPanel] = "handleStretchXPanel";
|
||||
overlayNames[handleStretchYPanel] = "handleStretchYPanel";
|
||||
overlayNames[handleStretchZPanel] = "handleStretchZPanel";
|
||||
|
||||
overlayNames[handleScaleLBNCube] = "handleScaleLBNCube";
|
||||
overlayNames[handleScaleRBNCube] = "handleScaleRBNCube";
|
||||
overlayNames[handleScaleLBFCube] = "handleScaleLBFCube";
|
||||
overlayNames[handleScaleRBFCube] = "handleScaleRBFCube";
|
||||
overlayNames[handleScaleLTNCube] = "handleScaleLTNCube";
|
||||
overlayNames[handleScaleRTNCube] = "handleScaleRTNCube";
|
||||
overlayNames[handleScaleLTFCube] = "handleScaleLTFCube";
|
||||
overlayNames[handleScaleRTFCube] = "handleScaleRTFCube";
|
||||
overlayNames[handleScaleCube] = "handleScaleCube";
|
||||
|
||||
overlayNames[handleScaleTREdge] = "handleScaleTREdge";
|
||||
overlayNames[handleScaleTLEdge] = "handleScaleTLEdge";
|
||||
overlayNames[handleScaleTFEdge] = "handleScaleTFEdge";
|
||||
overlayNames[handleScaleTNEdge] = "handleScaleTNEdge";
|
||||
overlayNames[handleScaleBREdge] = "handleScaleBREdge";
|
||||
overlayNames[handleScaleBLEdge] = "handleScaleBLEdge";
|
||||
overlayNames[handleScaleBFEdge] = "handleScaleBFEdge";
|
||||
overlayNames[handleScaleBNEdge] = "handleScaleBNEdge";
|
||||
overlayNames[handleScaleNREdge] = "handleScaleNREdge";
|
||||
overlayNames[handleScaleNLEdge] = "handleScaleNLEdge";
|
||||
overlayNames[handleScaleFREdge] = "handleScaleFREdge";
|
||||
overlayNames[handleScaleFLEdge] = "handleScaleFLEdge";
|
||||
overlayNames[handleBoundingTREdge] = "handleBoundingTREdge";
|
||||
overlayNames[handleBoundingTLEdge] = "handleBoundingTLEdge";
|
||||
overlayNames[handleBoundingTFEdge] = "handleBoundingTFEdge";
|
||||
overlayNames[handleBoundingTNEdge] = "handleBoundingTNEdge";
|
||||
overlayNames[handleBoundingBREdge] = "handleBoundingBREdge";
|
||||
overlayNames[handleBoundingBLEdge] = "handleBoundingBLEdge";
|
||||
overlayNames[handleBoundingBFEdge] = "handleBoundingBFEdge";
|
||||
overlayNames[handleBoundingBNEdge] = "handleBoundingBNEdge";
|
||||
overlayNames[handleBoundingNREdge] = "handleBoundingNREdge";
|
||||
overlayNames[handleBoundingNLEdge] = "handleBoundingNLEdge";
|
||||
overlayNames[handleBoundingFREdge] = "handleBoundingFREdge";
|
||||
overlayNames[handleBoundingFLEdge] = "handleBoundingFLEdge";
|
||||
|
||||
overlayNames[handleCloner] = "handleCloner";
|
||||
overlayNames[selectionBox] = "selectionBox";
|
||||
|
@ -1021,32 +998,25 @@ SelectionDisplay = (function() {
|
|||
case handleTranslateXCone:
|
||||
case handleTranslateXCylinder:
|
||||
case handleRotatePitchRing:
|
||||
case handleStretchXSphere:
|
||||
case handleStretchXCube:
|
||||
pickedColor = COLOR_RED;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
case handleTranslateYCone:
|
||||
case handleTranslateYCylinder:
|
||||
case handleRotateYawRing:
|
||||
case handleStretchYSphere:
|
||||
case handleStretchYCube:
|
||||
pickedColor = COLOR_GREEN;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
case handleTranslateZCone:
|
||||
case handleTranslateZCylinder:
|
||||
case handleRotateRollRing:
|
||||
case handleStretchZSphere:
|
||||
case handleStretchZCube:
|
||||
pickedColor = COLOR_BLUE;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
case handleScaleLBNCube:
|
||||
case handleScaleRBNCube:
|
||||
case handleScaleLBFCube:
|
||||
case handleScaleRBFCube:
|
||||
case handleScaleLTNCube:
|
||||
case handleScaleRTNCube:
|
||||
case handleScaleLTFCube:
|
||||
case handleScaleRTFCube:
|
||||
case handleScaleCube:
|
||||
pickedColor = COLOR_SCALE_CUBE;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
@ -1424,127 +1394,56 @@ SelectionDisplay = (function() {
|
|||
dimensions: arrowConeDimensions
|
||||
});
|
||||
|
||||
// UPDATE SCALE CUBES
|
||||
var scaleCubeOffsetX = SCALE_CUBE_OFFSET * dimensions.x;
|
||||
var scaleCubeOffsetY = SCALE_CUBE_OFFSET * dimensions.y;
|
||||
var scaleCubeOffsetZ = SCALE_CUBE_OFFSET * dimensions.z;
|
||||
var scaleCubeRotation = spaceMode === SPACE_LOCAL ? rotation : Quat.IDENTITY;
|
||||
var scaleLBNCubePosition = { x: -scaleCubeOffsetX, y: -scaleCubeOffsetY, z: -scaleCubeOffsetZ };
|
||||
scaleLBNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLBNCubePosition));
|
||||
var scaleLBNCubeToCamera = getDistanceToCamera(scaleLBNCubePosition);
|
||||
var scaleRBNCubePosition = { x: scaleCubeOffsetX, y: -scaleCubeOffsetY, z: -scaleCubeOffsetZ };
|
||||
scaleRBNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRBNCubePosition));
|
||||
var scaleRBNCubeToCamera = getDistanceToCamera(scaleRBNCubePosition);
|
||||
var scaleLBFCubePosition = { x: -scaleCubeOffsetX, y: -scaleCubeOffsetY, z: scaleCubeOffsetZ };
|
||||
scaleLBFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLBFCubePosition));
|
||||
var scaleLBFCubeToCamera = getDistanceToCamera(scaleLBFCubePosition);
|
||||
var scaleRBFCubePosition = { x: scaleCubeOffsetX, y: -scaleCubeOffsetY, z: scaleCubeOffsetZ };
|
||||
scaleRBFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRBFCubePosition));
|
||||
var scaleRBFCubeToCamera = getDistanceToCamera(scaleRBFCubePosition);
|
||||
var scaleLTNCubePosition = { x: -scaleCubeOffsetX, y: scaleCubeOffsetY, z: -scaleCubeOffsetZ };
|
||||
scaleLTNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLTNCubePosition));
|
||||
var scaleLTNCubeToCamera = getDistanceToCamera(scaleLTNCubePosition);
|
||||
var scaleRTNCubePosition = { x: scaleCubeOffsetX, y: scaleCubeOffsetY, z: -scaleCubeOffsetZ };
|
||||
scaleRTNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRTNCubePosition));
|
||||
var scaleRTNCubeToCamera = getDistanceToCamera(scaleRTNCubePosition);
|
||||
var scaleLTFCubePosition = { x: -scaleCubeOffsetX, y: scaleCubeOffsetY, z: scaleCubeOffsetZ };
|
||||
scaleLTFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLTFCubePosition));
|
||||
var scaleLTFCubeToCamera = getDistanceToCamera(scaleLTFCubePosition);
|
||||
var scaleRTFCubePosition = { x: scaleCubeOffsetX, y: scaleCubeOffsetY, z: scaleCubeOffsetZ };
|
||||
scaleRTFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRTFCubePosition));
|
||||
var scaleRTFCubeToCamera = getDistanceToCamera(scaleRTFCubePosition);
|
||||
|
||||
var scaleCubeToCamera = Math.min(scaleLBNCubeToCamera, scaleRBNCubeToCamera, scaleLBFCubeToCamera,
|
||||
scaleRBFCubeToCamera, scaleLTNCubeToCamera, scaleRTNCubeToCamera,
|
||||
scaleLTFCubeToCamera, scaleRTFCubeToCamera);
|
||||
var scaleCubeDimension = scaleCubeToCamera * SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE;
|
||||
var scaleCubeDimensions = { x: scaleCubeDimension, y: scaleCubeDimension, z: scaleCubeDimension };
|
||||
|
||||
Overlays.editOverlay(handleScaleLBNCube, {
|
||||
position: scaleLBNCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleRBNCube, {
|
||||
position: scaleRBNCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleLBFCube, {
|
||||
position: scaleLBFCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleRBFCube, {
|
||||
position: scaleRBFCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleLTNCube, {
|
||||
position: scaleLTNCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleRTNCube, {
|
||||
position: scaleRTNCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleLTFCube, {
|
||||
position: scaleLTFCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleScaleRTFCube, {
|
||||
position: scaleRTFCubePosition,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
|
||||
// UPDATE SCALE EDGES
|
||||
Overlays.editOverlay(handleScaleTREdge, { start: scaleRTNCubePosition, end: scaleRTFCubePosition });
|
||||
Overlays.editOverlay(handleScaleTLEdge, { start: scaleLTNCubePosition, end: scaleLTFCubePosition });
|
||||
Overlays.editOverlay(handleScaleTFEdge, { start: scaleLTFCubePosition, end: scaleRTFCubePosition });
|
||||
Overlays.editOverlay(handleScaleTNEdge, { start: scaleLTNCubePosition, end: scaleRTNCubePosition });
|
||||
Overlays.editOverlay(handleScaleBREdge, { start: scaleRBNCubePosition, end: scaleRBFCubePosition });
|
||||
Overlays.editOverlay(handleScaleBLEdge, { start: scaleLBNCubePosition, end: scaleLBFCubePosition });
|
||||
Overlays.editOverlay(handleScaleBFEdge, { start: scaleLBFCubePosition, end: scaleRBFCubePosition });
|
||||
Overlays.editOverlay(handleScaleBNEdge, { start: scaleLBNCubePosition, end: scaleRBNCubePosition });
|
||||
Overlays.editOverlay(handleScaleNREdge, { start: scaleRTNCubePosition, end: scaleRBNCubePosition });
|
||||
Overlays.editOverlay(handleScaleNLEdge, { start: scaleLTNCubePosition, end: scaleLBNCubePosition });
|
||||
Overlays.editOverlay(handleScaleFREdge, { start: scaleRTFCubePosition, end: scaleRBFCubePosition });
|
||||
Overlays.editOverlay(handleScaleFLEdge, { start: scaleLTFCubePosition, end: scaleLBFCubePosition });
|
||||
|
||||
// UPDATE STRETCH SPHERES
|
||||
var stretchSphereDimension = rotateDimension * STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE /
|
||||
// UPDATE SCALE CUBE
|
||||
var scaleCubeRotation = spaceMode === SPACE_LOCAL ? rotation : Quat.IDENTITY;
|
||||
var scaleCubeDimension = rotateDimension * SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE /
|
||||
ROTATE_RING_CAMERA_DISTANCE_MULTIPLE;
|
||||
var stretchSphereDimensions = { x: stretchSphereDimension, y: stretchSphereDimension, z: stretchSphereDimension };
|
||||
var stretchSphereOffset = rotateDimension * STRETCH_SPHERE_OFFSET / ROTATE_RING_CAMERA_DISTANCE_MULTIPLE;
|
||||
var stretchXPosition = { x: stretchSphereOffset, y: 0, z: 0 };
|
||||
stretchXPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchXPosition));
|
||||
Overlays.editOverlay(handleStretchXSphere, {
|
||||
position: stretchXPosition,
|
||||
dimensions: stretchSphereDimensions
|
||||
});
|
||||
var stretchYPosition = { x: 0, y: stretchSphereOffset, z: 0 };
|
||||
stretchYPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchYPosition));
|
||||
Overlays.editOverlay(handleStretchYSphere, {
|
||||
position: stretchYPosition,
|
||||
dimensions: stretchSphereDimensions
|
||||
});
|
||||
var stretchZPosition = { x: 0, y: 0, z: stretchSphereOffset };
|
||||
stretchZPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchZPosition));
|
||||
Overlays.editOverlay(handleStretchZSphere, {
|
||||
position: stretchZPosition,
|
||||
dimensions: stretchSphereDimensions
|
||||
var scaleCubeDimensions = { x: scaleCubeDimension, y: scaleCubeDimension, z: scaleCubeDimension };
|
||||
Overlays.editOverlay(handleScaleCube, {
|
||||
position: position,
|
||||
rotation: scaleCubeRotation,
|
||||
dimensions: scaleCubeDimensions
|
||||
});
|
||||
|
||||
// UPDATE BOUNDING BOX EDGES
|
||||
var edgeOffsetX = BOUNDING_EDGE_OFFSET * dimensions.x;
|
||||
var edgeOffsetY = BOUNDING_EDGE_OFFSET * dimensions.y;
|
||||
var edgeOffsetZ = BOUNDING_EDGE_OFFSET * dimensions.z;
|
||||
var LBNPosition = { x: -edgeOffsetX, y: -edgeOffsetY, z: -edgeOffsetZ };
|
||||
LBNPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, LBNPosition));
|
||||
var RBNPosition = { x: edgeOffsetX, y: -edgeOffsetY, z: -edgeOffsetZ };
|
||||
RBNPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, RBNPosition));
|
||||
var LBFPosition = { x: -edgeOffsetX, y: -edgeOffsetY, z: edgeOffsetZ };
|
||||
LBFPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, LBFPosition));
|
||||
var RBFPosition = { x: edgeOffsetX, y: -edgeOffsetY, z: edgeOffsetZ };
|
||||
RBFPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, RBFPosition));
|
||||
var LTNPosition = { x: -edgeOffsetX, y: edgeOffsetY, z: -edgeOffsetZ };
|
||||
LTNPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, LTNPosition));
|
||||
var RTNPosition = { x: edgeOffsetX, y: edgeOffsetY, z: -edgeOffsetZ };
|
||||
RTNPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, RTNPosition));
|
||||
var LTFPosition = { x: -edgeOffsetX, y: edgeOffsetY, z: edgeOffsetZ };
|
||||
LTFPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, LTFPosition));
|
||||
var RTFPosition = { x: edgeOffsetX, y: edgeOffsetY, z: edgeOffsetZ };
|
||||
RTFPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, RTFPosition));
|
||||
Overlays.editOverlay(handleBoundingTREdge, { start: RTNPosition, end: RTFPosition });
|
||||
Overlays.editOverlay(handleBoundingTLEdge, { start: LTNPosition, end: LTFPosition });
|
||||
Overlays.editOverlay(handleBoundingTFEdge, { start: LTFPosition, end: RTFPosition });
|
||||
Overlays.editOverlay(handleBoundingTNEdge, { start: LTNPosition, end: RTNPosition });
|
||||
Overlays.editOverlay(handleBoundingBREdge, { start: RBNPosition, end: RBFPosition });
|
||||
Overlays.editOverlay(handleBoundingBLEdge, { start: LBNPosition, end: LBFPosition });
|
||||
Overlays.editOverlay(handleBoundingBFEdge, { start: LBFPosition, end: RBFPosition });
|
||||
Overlays.editOverlay(handleBoundingBNEdge, { start: LBNPosition, end: RBNPosition });
|
||||
Overlays.editOverlay(handleBoundingNREdge, { start: RTNPosition, end: RBNPosition });
|
||||
Overlays.editOverlay(handleBoundingNLEdge, { start: LTNPosition, end: LBNPosition });
|
||||
Overlays.editOverlay(handleBoundingFREdge, { start: RTFPosition, end: RBFPosition });
|
||||
Overlays.editOverlay(handleBoundingFLEdge, { start: LTFPosition, end: LBFPosition });
|
||||
|
||||
// UPDATE STRETCH HIGHLIGHT PANELS
|
||||
var scaleRBFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRBFCubePosition);
|
||||
var scaleRTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTFCubePosition);
|
||||
var scaleLTNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleLTNCubePosition);
|
||||
var scaleRTNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTNCubePosition);
|
||||
var stretchPanelXDimensions = Vec3.subtract(scaleRTNCubePositionRotated, scaleRBFCubePositionRotated);
|
||||
var RBFPositionRotated = Vec3.multiplyQbyV(rotationInverse, RBFPosition);
|
||||
var RTFPositionRotated = Vec3.multiplyQbyV(rotationInverse, RTFPosition);
|
||||
var LTNPositionRotated = Vec3.multiplyQbyV(rotationInverse, LTNPosition);
|
||||
var RTNPositionRotated = Vec3.multiplyQbyV(rotationInverse, RTNPosition);
|
||||
var stretchPanelXDimensions = Vec3.subtract(RTNPositionRotated, RBFPositionRotated);
|
||||
var tempY = Math.abs(stretchPanelXDimensions.y);
|
||||
stretchPanelXDimensions.x = STRETCH_PANEL_WIDTH;
|
||||
stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z);
|
||||
|
@ -1555,7 +1454,7 @@ SelectionDisplay = (function() {
|
|||
rotation: rotationZ,
|
||||
dimensions: stretchPanelXDimensions
|
||||
});
|
||||
var stretchPanelYDimensions = Vec3.subtract(scaleLTNCubePositionRotated, scaleRTFCubePositionRotated);
|
||||
var stretchPanelYDimensions = Vec3.subtract(LTNPositionRotated, RTFPositionRotated);
|
||||
var tempX = Math.abs(stretchPanelYDimensions.x);
|
||||
stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z);
|
||||
stretchPanelYDimensions.y = STRETCH_PANEL_WIDTH;
|
||||
|
@ -1566,7 +1465,7 @@ SelectionDisplay = (function() {
|
|||
rotation: rotationY,
|
||||
dimensions: stretchPanelYDimensions
|
||||
});
|
||||
var stretchPanelZDimensions = Vec3.subtract(scaleLTNCubePositionRotated, scaleRBFCubePositionRotated);
|
||||
var stretchPanelZDimensions = Vec3.subtract(LTNPositionRotated, RBFPositionRotated);
|
||||
tempX = Math.abs(stretchPanelZDimensions.x);
|
||||
stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y);
|
||||
stretchPanelZDimensions.y = tempX;
|
||||
|
@ -1578,6 +1477,46 @@ SelectionDisplay = (function() {
|
|||
dimensions: stretchPanelZDimensions
|
||||
});
|
||||
|
||||
// UPDATE STRETCH CUBES
|
||||
var stretchCubeDimension = rotateDimension * STRETCH_CUBE_CAMERA_DISTANCE_MULTIPLE /
|
||||
ROTATE_RING_CAMERA_DISTANCE_MULTIPLE;
|
||||
var stretchCubeDimensions = { x: stretchCubeDimension, y: stretchCubeDimension, z: stretchCubeDimension };
|
||||
var stretchCubeOffset = rotateDimension * STRETCH_CUBE_OFFSET / ROTATE_RING_CAMERA_DISTANCE_MULTIPLE;
|
||||
var stretchXPosition, stretchYPosition, stretchZPosition;
|
||||
if (isActiveTool(handleStretchXCube)) {
|
||||
stretchXPosition = Vec3.subtract(stretchPanelXPosition, activeStretchCubePanelOffset);
|
||||
} else {
|
||||
stretchXPosition = { x: stretchCubeOffset, y: 0, z: 0 };
|
||||
stretchXPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchXPosition));
|
||||
}
|
||||
if (isActiveTool(handleStretchYCube)) {
|
||||
stretchYPosition = Vec3.subtract(stretchPanelYPosition, activeStretchCubePanelOffset);
|
||||
} else {
|
||||
stretchYPosition = { x: 0, y: stretchCubeOffset, z: 0 };
|
||||
stretchYPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchYPosition));
|
||||
}
|
||||
if (isActiveTool(handleStretchZCube)) {
|
||||
stretchZPosition = Vec3.subtract(stretchPanelZPosition, activeStretchCubePanelOffset);
|
||||
} else {
|
||||
stretchZPosition = { x: 0, y: 0, z: stretchCubeOffset };
|
||||
stretchZPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchZPosition));
|
||||
}
|
||||
Overlays.editOverlay(handleStretchXCube, {
|
||||
position: stretchXPosition,
|
||||
rotation: rotationX,
|
||||
dimensions: stretchCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleStretchYCube, {
|
||||
position: stretchYPosition,
|
||||
rotation: rotationY,
|
||||
dimensions: stretchCubeDimensions
|
||||
});
|
||||
Overlays.editOverlay(handleStretchZCube, {
|
||||
position: stretchZPosition,
|
||||
rotation: rotationZ,
|
||||
dimensions: stretchCubeDimensions
|
||||
});
|
||||
|
||||
// UPDATE SELECTION BOX (CURRENTLY INVISIBLE WITH 0 ALPHA FOR TRANSLATE XZ TOOL)
|
||||
var inModeRotate = isActiveTool(handleRotatePitchRing) ||
|
||||
isActiveTool(handleRotateYawRing) ||
|
||||
|
@ -1622,20 +1561,15 @@ SelectionDisplay = (function() {
|
|||
that.setHandleRotateRollVisible(!activeTool || isActiveTool(handleRotateRollRing));
|
||||
|
||||
var showScaleStretch = !activeTool && SelectionManager.selections.length === 1 && spaceMode === SPACE_LOCAL;
|
||||
that.setHandleStretchXVisible(showScaleStretch || isActiveTool(handleStretchXSphere));
|
||||
that.setHandleStretchYVisible(showScaleStretch || isActiveTool(handleStretchYSphere));
|
||||
that.setHandleStretchZVisible(showScaleStretch || isActiveTool(handleStretchZSphere));
|
||||
that.setHandleScaleCubeVisible(showScaleStretch || isActiveTool(handleScaleLBNCube) ||
|
||||
isActiveTool(handleScaleRBNCube) || isActiveTool(handleScaleLBFCube) ||
|
||||
isActiveTool(handleScaleRBFCube) || isActiveTool(handleScaleLTNCube) ||
|
||||
isActiveTool(handleScaleRTNCube) || isActiveTool(handleScaleLTFCube) ||
|
||||
isActiveTool(handleScaleRTFCube) || isActiveTool(handleStretchXSphere) ||
|
||||
isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere));
|
||||
that.setHandleStretchXVisible(showScaleStretch || isActiveTool(handleStretchXCube));
|
||||
that.setHandleStretchYVisible(showScaleStretch || isActiveTool(handleStretchYCube));
|
||||
that.setHandleStretchZVisible(showScaleStretch || isActiveTool(handleStretchZCube));
|
||||
that.setHandleScaleCubeVisible(showScaleStretch || isActiveTool(handleScaleCube));
|
||||
|
||||
var showOutlineForZone = (SelectionManager.selections.length === 1 &&
|
||||
typeof SelectionManager.savedProperties[SelectionManager.selections[0]] !== "undefined" &&
|
||||
SelectionManager.savedProperties[SelectionManager.selections[0]].type === "Zone");
|
||||
that.setHandleScaleEdgeVisible(showOutlineForZone || (!isActiveTool(handleRotatePitchRing) &&
|
||||
that.setHandleBoundingEdgeVisible(showOutlineForZone || (!isActiveTool(handleRotatePitchRing) &&
|
||||
!isActiveTool(handleRotateYawRing) &&
|
||||
!isActiveTool(handleRotateRollRing)));
|
||||
|
||||
|
@ -1721,47 +1655,40 @@ SelectionDisplay = (function() {
|
|||
};
|
||||
|
||||
that.setHandleStretchXVisible = function(isVisible) {
|
||||
Overlays.editOverlay(handleStretchXSphere, { visible: isVisible });
|
||||
Overlays.editOverlay(handleStretchXCube, { visible: isVisible });
|
||||
};
|
||||
|
||||
that.setHandleStretchYVisible = function(isVisible) {
|
||||
Overlays.editOverlay(handleStretchYSphere, { visible: isVisible });
|
||||
Overlays.editOverlay(handleStretchYCube, { visible: isVisible });
|
||||
};
|
||||
|
||||
that.setHandleStretchZVisible = function(isVisible) {
|
||||
Overlays.editOverlay(handleStretchZSphere, { visible: isVisible });
|
||||
Overlays.editOverlay(handleStretchZCube, { visible: isVisible });
|
||||
};
|
||||
|
||||
// FUNCTION: SET HANDLE SCALE VISIBLE
|
||||
that.setHandleScaleVisible = function(isVisible) {
|
||||
that.setHandleScaleCubeVisible(isVisible);
|
||||
that.setHandleScaleEdgeVisible(isVisible);
|
||||
that.setHandleBoundingEdgeVisible(isVisible);
|
||||
};
|
||||
|
||||
that.setHandleScaleCubeVisible = function(isVisible) {
|
||||
Overlays.editOverlay(handleScaleLBNCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleRBNCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleLBFCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleRBFCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleLTNCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleRTNCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleLTFCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleRTFCube, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleCube, { visible: isVisible });
|
||||
};
|
||||
|
||||
that.setHandleScaleEdgeVisible = function(isVisible) {
|
||||
Overlays.editOverlay(handleScaleTREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleTLEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleTFEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleTNEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleBREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleBLEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleBFEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleBNEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleNREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleNLEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleFREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleScaleFLEdge, { visible: isVisible });
|
||||
that.setHandleBoundingEdgeVisible = function(isVisible) {
|
||||
Overlays.editOverlay(handleBoundingTREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingTLEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingTFEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingTNEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingBREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingBLEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingBFEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingBNEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingNREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingNLEdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingFREdge, { visible: isVisible });
|
||||
Overlays.editOverlay(handleBoundingFLEdge, { visible: isVisible });
|
||||
};
|
||||
|
||||
// FUNCTION: SET HANDLE CLONER VISIBLE
|
||||
|
@ -2123,7 +2050,7 @@ SelectionDisplay = (function() {
|
|||
};
|
||||
|
||||
// TOOL DEFINITION: HANDLE STRETCH TOOL
|
||||
function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset, stretchPanel, scaleHandle) {
|
||||
function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset, stretchPanel, cubeHandle) {
|
||||
var directionFor3DStretch = directionVec;
|
||||
var distanceFor3DStretch = 0;
|
||||
var DISTANCE_INFLUENCE_THRESHOLD = 1.2;
|
||||
|
@ -2155,8 +2082,11 @@ SelectionDisplay = (function() {
|
|||
var pickRayPosition3D = null;
|
||||
var rotation = null;
|
||||
var previousPickRay = null;
|
||||
var beginMouseEvent = null;
|
||||
|
||||
var onBegin = function(event, pickRay, pickResult) {
|
||||
var onBegin = function(event, pickRay, pickResult) {
|
||||
var proportional = directionEnum === STRETCH_DIRECTION.ALL;
|
||||
|
||||
var properties = Entities.getEntityProperties(SelectionManager.selections[0]);
|
||||
initialProperties = properties;
|
||||
rotation = (spaceMode === SPACE_LOCAL) ? properties.rotation : Quat.IDENTITY;
|
||||
|
@ -2244,9 +2174,7 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
|
||||
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
|
||||
lastPick = rayPlaneIntersection(pickRay,
|
||||
pickRayPosition,
|
||||
planeNormal);
|
||||
lastPick = rayPlaneIntersection(pickRay, pickRayPosition, planeNormal);
|
||||
|
||||
var planeNormal3D = {
|
||||
x: 0,
|
||||
|
@ -2274,10 +2202,7 @@ SelectionDisplay = (function() {
|
|||
if (stretchPanel !== null) {
|
||||
Overlays.editOverlay(stretchPanel, { visible: true });
|
||||
}
|
||||
if (scaleHandle !== null) {
|
||||
Overlays.editOverlay(scaleHandle, { color: COLOR_SCALE_CUBE_SELECTED });
|
||||
}
|
||||
|
||||
|
||||
var collisionToRemove = "myAvatar";
|
||||
if (properties.collidesWith.indexOf(collisionToRemove) > -1) {
|
||||
var newCollidesWith = properties.collidesWith.replace(collisionToRemove, "");
|
||||
|
@ -2285,16 +2210,20 @@ SelectionDisplay = (function() {
|
|||
that.replaceCollisionsAfterStretch = true;
|
||||
}
|
||||
|
||||
if (!proportional) {
|
||||
var stretchCubePosition = Overlays.getProperty(cubeHandle, "position");
|
||||
var stretchPanelPosition = Overlays.getProperty(stretchPanel, "position");
|
||||
activeStretchCubePanelOffset = Vec3.subtract(stretchPanelPosition, stretchCubePosition);
|
||||
}
|
||||
|
||||
previousPickRay = pickRay;
|
||||
beginMouseEvent = event;
|
||||
};
|
||||
|
||||
var onEnd = function(event, reason) {
|
||||
if (stretchPanel !== null) {
|
||||
Overlays.editOverlay(stretchPanel, { visible: false });
|
||||
}
|
||||
if (scaleHandle !== null) {
|
||||
Overlays.editOverlay(scaleHandle, { color: COLOR_SCALE_CUBE });
|
||||
}
|
||||
|
||||
if (that.replaceCollisionsAfterStretch) {
|
||||
var newCollidesWith = SelectionManager.savedProperties[SelectionManager.selections[0]].collidesWith;
|
||||
|
@ -2302,6 +2231,8 @@ SelectionDisplay = (function() {
|
|||
that.replaceCollisionsAfterStretch = false;
|
||||
}
|
||||
|
||||
activeStretchCubePanelOffset = null;
|
||||
|
||||
pushCommandForSelections();
|
||||
};
|
||||
|
||||
|
@ -2351,34 +2282,27 @@ SelectionDisplay = (function() {
|
|||
vector = grid.snapToSpacing(vector);
|
||||
|
||||
var changeInDimensions = Vec3.multiply(NEGATE_VECTOR, vec3Mult(localSigns, vector));
|
||||
if (directionEnum === STRETCH_DIRECTION.ALL) {
|
||||
var toCameraDistance = getDistanceToCamera(position);
|
||||
var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE;
|
||||
changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple);
|
||||
}
|
||||
|
||||
|
||||
var newDimensions;
|
||||
if (proportional) {
|
||||
var absoluteX = Math.abs(changeInDimensions.x);
|
||||
var absoluteY = Math.abs(changeInDimensions.y);
|
||||
var absoluteZ = Math.abs(changeInDimensions.z);
|
||||
var percentChange = 0;
|
||||
if (absoluteX > absoluteY && absoluteX > absoluteZ) {
|
||||
percentChange = changeInDimensions.x / initialProperties.dimensions.x;
|
||||
percentChange = changeInDimensions.x / initialDimensions.x;
|
||||
} else if (absoluteY > absoluteZ) {
|
||||
percentChange = changeInDimensions.y / initialProperties.dimensions.y;
|
||||
percentChange = changeInDimensions.y / initialDimensions.y;
|
||||
} else {
|
||||
percentChange = changeInDimensions.z / initialProperties.dimensions.z;
|
||||
percentChange = changeInDimensions.z / initialDimensions.z;
|
||||
}
|
||||
var viewportDimensions = Controller.getViewportDimensions();
|
||||
var mouseXDifference = (event.x - beginMouseEvent.x) / viewportDimensions.x;
|
||||
var mouseYDifference = (beginMouseEvent.y - event.y) / viewportDimensions.y;
|
||||
var mouseDifference = mouseXDifference + mouseYDifference;
|
||||
var toCameraDistance = getDistanceToCamera(position);
|
||||
var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE;
|
||||
var dimensionChange = mouseDifference * dimensionsMultiple;
|
||||
var averageInitialDimension = (initialDimensions.x + initialDimensions.y + initialDimensions.z) / 3;
|
||||
percentChange = dimensionChange / averageInitialDimension;
|
||||
percentChange += 1.0;
|
||||
newDimensions = Vec3.multiply(percentChange, initialDimensions);
|
||||
newDimensions.x = Math.abs(newDimensions.x);
|
||||
newDimensions.y = Math.abs(newDimensions.y);
|
||||
newDimensions.z = Math.abs(newDimensions.z);
|
||||
} else {
|
||||
newDimensions = Vec3.sum(initialDimensions, changeInDimensions);
|
||||
}
|
||||
|
||||
|
||||
var minimumDimension = directionEnum ===
|
||||
STRETCH_DIRECTION.ALL ? STRETCH_ALL_MINIMUM_DIMENSION : STRETCH_MINIMUM_DIMENSION;
|
||||
if (newDimensions.x < minimumDimension) {
|
||||
|
@ -2393,9 +2317,9 @@ SelectionDisplay = (function() {
|
|||
newDimensions.z = minimumDimension;
|
||||
changeInDimensions.z = minimumDimension - initialDimensions.z;
|
||||
}
|
||||
|
||||
|
||||
var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(localDeltaPivot, changeInDimensions));
|
||||
if (directionEnum === STRETCH_DIRECTION.ALL) {
|
||||
if (proportional) {
|
||||
changeInPosition = { x: 0, y: 0, z: 0 };
|
||||
}
|
||||
var newPosition = Vec3.sum(initialPosition, changeInPosition);
|
||||
|
@ -2429,52 +2353,30 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
|
||||
function addHandleStretchTool(overlay, mode, directionEnum) {
|
||||
var directionVector, offset, stretchPanel;
|
||||
var directionVector, offset, stretchPanel, handleStretchCube;
|
||||
if (directionEnum === STRETCH_DIRECTION.X) {
|
||||
stretchPanel = handleStretchXPanel;
|
||||
handleStretchCube = handleStretchXCube;
|
||||
directionVector = { x: -1, y: 0, z: 0 };
|
||||
} else if (directionEnum === STRETCH_DIRECTION.Y) {
|
||||
stretchPanel = handleStretchYPanel;
|
||||
handleStretchCube = handleStretchYCube;
|
||||
directionVector = { x: 0, y: -1, z: 0 };
|
||||
} else if (directionEnum === STRETCH_DIRECTION.Z) {
|
||||
stretchPanel = handleStretchZPanel;
|
||||
handleStretchCube = handleStretchZCube;
|
||||
directionVector = { x: 0, y: 0, z: -1 };
|
||||
}
|
||||
offset = Vec3.multiply(directionVector, NEGATE_VECTOR);
|
||||
var tool = makeStretchTool(mode, directionEnum, directionVector, directionVector, offset, stretchPanel, null);
|
||||
var tool = makeStretchTool(mode, directionEnum, directionVector, directionVector, offset, stretchPanel, handleStretchCube);
|
||||
return addHandleTool(overlay, tool);
|
||||
}
|
||||
|
||||
// TOOL DEFINITION: HANDLE SCALE TOOL
|
||||
function addHandleScaleTool(overlay, mode, directionEnum) {
|
||||
var directionVector, offset, selectedHandle;
|
||||
if (directionEnum === SCALE_DIRECTION.LBN) {
|
||||
directionVector = { x: 1, y: 1, z: 1 };
|
||||
selectedHandle = handleScaleLBNCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.RBN) {
|
||||
directionVector = { x: -1, y: 1, z: 1 };
|
||||
selectedHandle = handleScaleRBNCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.LBF) {
|
||||
directionVector = { x: 1, y: 1, z: -1 };
|
||||
selectedHandle = handleScaleLBFCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.RBF) {
|
||||
directionVector = { x: -1, y: 1, z: -1 };
|
||||
selectedHandle = handleScaleRBFCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.LTN) {
|
||||
directionVector = { x: 1, y: -1, z: 1 };
|
||||
selectedHandle = handleScaleLTNCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.RTN) {
|
||||
directionVector = { x: -1, y: -1, z: 1 };
|
||||
selectedHandle = handleScaleRTNCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.LTF) {
|
||||
directionVector = { x: 1, y: -1, z: -1 };
|
||||
selectedHandle = handleScaleLTFCube;
|
||||
} else if (directionEnum === SCALE_DIRECTION.RTF) {
|
||||
directionVector = { x: -1, y: -1, z: -1 };
|
||||
selectedHandle = handleScaleRTFCube;
|
||||
}
|
||||
offset = Vec3.multiply(directionVector, NEGATE_VECTOR);
|
||||
var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVector, directionVector, offset, null, selectedHandle);
|
||||
function addHandleScaleTool(overlay, mode) {
|
||||
var directionVector = { x:0, y:0, z:0 };
|
||||
var offset = { x:0, y:0, z:0 };
|
||||
var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVector, directionVector, offset, null, handleScaleCube);
|
||||
return addHandleTool(overlay, tool);
|
||||
}
|
||||
|
||||
|
@ -2747,18 +2649,11 @@ SelectionDisplay = (function() {
|
|||
addHandleRotateTool(handleRotateYawRing, "ROTATE_YAW", ROTATE_DIRECTION.YAW);
|
||||
addHandleRotateTool(handleRotateRollRing, "ROTATE_ROLL", ROTATE_DIRECTION.ROLL);
|
||||
|
||||
addHandleStretchTool(handleStretchXSphere, "STRETCH_X", STRETCH_DIRECTION.X);
|
||||
addHandleStretchTool(handleStretchYSphere, "STRETCH_Y", STRETCH_DIRECTION.Y);
|
||||
addHandleStretchTool(handleStretchZSphere, "STRETCH_Z", STRETCH_DIRECTION.Z);
|
||||
|
||||
addHandleScaleTool(handleScaleLBNCube, "SCALE_LBN", SCALE_DIRECTION.LBN);
|
||||
addHandleScaleTool(handleScaleRBNCube, "SCALE_RBN", SCALE_DIRECTION.RBN);
|
||||
addHandleScaleTool(handleScaleLBFCube, "SCALE_LBF", SCALE_DIRECTION.LBF);
|
||||
addHandleScaleTool(handleScaleRBFCube, "SCALE_RBF", SCALE_DIRECTION.RBF);
|
||||
addHandleScaleTool(handleScaleLTNCube, "SCALE_LTN", SCALE_DIRECTION.LTN);
|
||||
addHandleScaleTool(handleScaleRTNCube, "SCALE_RTN", SCALE_DIRECTION.RTN);
|
||||
addHandleScaleTool(handleScaleLTFCube, "SCALE_LTF", SCALE_DIRECTION.LTF);
|
||||
addHandleScaleTool(handleScaleRTFCube, "SCALE_RTF", SCALE_DIRECTION.RTF);
|
||||
addHandleStretchTool(handleStretchXCube, "STRETCH_X", STRETCH_DIRECTION.X);
|
||||
addHandleStretchTool(handleStretchYCube, "STRETCH_Y", STRETCH_DIRECTION.Y);
|
||||
addHandleStretchTool(handleStretchZCube, "STRETCH_Z", STRETCH_DIRECTION.Z);
|
||||
|
||||
addHandleScaleTool(handleScaleCube, "SCALE");
|
||||
|
||||
return that;
|
||||
}());
|
||||
|
|