mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:25:52 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into yellow
This commit is contained in:
commit
f30eb919c7
29 changed files with 345 additions and 110 deletions
|
@ -33,7 +33,7 @@ If you do not wish to use the Python installation bundled with Visual Studio, yo
|
||||||
|
|
||||||
Download and install the latest version of CMake 3.9.
|
Download and install the latest version of CMake 3.9.
|
||||||
|
|
||||||
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.9 Version page](https://cmake.org/files/v3.9/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
|
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.14 Version page](https://cmake.org/files/v3.14/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
|
||||||
|
|
||||||
### Step 3. Create VCPKG environment variable
|
### Step 3. Create VCPKG environment variable
|
||||||
In the next step, you will use CMake to build High Fidelity. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them.
|
In the next step, you will use CMake to build High Fidelity. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them.
|
||||||
|
|
|
@ -58,6 +58,7 @@ Windows.Window {
|
||||||
}
|
}
|
||||||
QmlSurface.load(source, contentHolder, function(newObject) {
|
QmlSurface.load(source, contentHolder, function(newObject) {
|
||||||
dynamicContent = newObject;
|
dynamicContent = newObject;
|
||||||
|
updateInteractiveWindowSizeForMode();
|
||||||
if (dynamicContent && dynamicContent.anchors) {
|
if (dynamicContent && dynamicContent.anchors) {
|
||||||
dynamicContent.anchors.fill = contentHolder;
|
dynamicContent.anchors.fill = contentHolder;
|
||||||
}
|
}
|
||||||
|
@ -81,10 +82,12 @@ Windows.Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateInteractiveWindowSizeForMode() {
|
function updateInteractiveWindowSizeForMode() {
|
||||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
root.width = interactiveWindowSize.width;
|
||||||
width = interactiveWindowSize.width;
|
root.height = interactiveWindowSize.height;
|
||||||
height = interactiveWindowSize.height;
|
contentHolder.width = interactiveWindowSize.width;
|
||||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
contentHolder.height = interactiveWindowSize.height;
|
||||||
|
|
||||||
|
if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
||||||
nativeWindow.width = interactiveWindowSize.width;
|
nativeWindow.width = interactiveWindowSize.width;
|
||||||
nativeWindow.height = interactiveWindowSize.height;
|
nativeWindow.height = interactiveWindowSize.height;
|
||||||
}
|
}
|
||||||
|
@ -134,6 +137,9 @@ Windows.Window {
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
id: root;
|
id: root;
|
||||||
|
width: interactiveWindowSize.width
|
||||||
|
height: interactiveWindowSize.height
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: hifi.colors.baseGray
|
color: hifi.colors.baseGray
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -75,21 +75,31 @@ ListModel {
|
||||||
// 1: equivalent to paging when reaching end (and not before).
|
// 1: equivalent to paging when reaching end (and not before).
|
||||||
// 0: don't getNextPage on scroll at all here. The application code will do it.
|
// 0: don't getNextPage on scroll at all here. The application code will do it.
|
||||||
property real pageAhead: 2.0;
|
property real pageAhead: 2.0;
|
||||||
function needsEarlyYFetch() {
|
function onContentXChanged() {
|
||||||
return flickable
|
if (flickable &&
|
||||||
&& !flickable.atYBeginning
|
!flickable.atXBeginning &&
|
||||||
&& (flickable.contentY - flickable.originY) >= (flickable.contentHeight - (pageAhead * flickable.height));
|
(flickable.contentX - flickable.originX) >= (flickable.contentWidth - (pageAhead * flickable.width))) {
|
||||||
|
getNextPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function needsEarlyXFetch() {
|
function onContentYChanged() {
|
||||||
return flickable
|
if (flickable &&
|
||||||
&& !flickable.atXBeginning
|
!flickable.atYBeginning &&
|
||||||
&& (flickable.contentX - flickable.originX) >= (flickable.contentWidth - (pageAhead * flickable.width));
|
(flickable.contentY - flickable.originY) >= (flickable.contentHeight - (pageAhead * flickable.height))) {
|
||||||
|
getNextPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function getNextPageIfHorizontalScroll() {
|
function onWidthChanged() {
|
||||||
if (needsEarlyXFetch()) { getNextPage(); }
|
if (flickable &&
|
||||||
|
(flickable.contentX - flickable.originX) >= (flickable.contentWidth - (pageAhead * flickable.width))) {
|
||||||
|
getNextPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function getNextPageIfVerticalScroll() {
|
function onHeightChanged() {
|
||||||
if (needsEarlyYFetch()) { getNextPage(); }
|
if (flickable &&
|
||||||
|
(flickable.contentY - flickable.originY) >= (flickable.contentHeight - (pageAhead * flickable.height))) {
|
||||||
|
getNextPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function needsMoreHorizontalResults() {
|
function needsMoreHorizontalResults() {
|
||||||
return flickable
|
return flickable
|
||||||
|
@ -118,8 +128,10 @@ ListModel {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
if (flickable && pageAhead > 0.0) {
|
if (flickable && pageAhead > 0.0) {
|
||||||
// Pun: Scrollers are usually one direction or another, such that only one of the following will actually fire.
|
// Pun: Scrollers are usually one direction or another, such that only one of the following will actually fire.
|
||||||
flickable.contentXChanged.connect(getNextPageIfHorizontalScroll);
|
flickable.contentXChanged.connect(onContentXChanged);
|
||||||
flickable.contentYChanged.connect(getNextPageIfVerticalScroll);
|
flickable.contentYChanged.connect(onContentYChanged);
|
||||||
|
flickable.widthChanged.connect(onWidthChanged);
|
||||||
|
flickable.heightChanged.connect(onHeightChanged);
|
||||||
flickable.contentWidthChanged.connect(getNextPageIfNotEnoughHorizontalResults);
|
flickable.contentWidthChanged.connect(getNextPageIfNotEnoughHorizontalResults);
|
||||||
flickable.contentHeightChanged.connect(getNextPageIfNotEnoughVerticalResults);
|
flickable.contentHeightChanged.connect(getNextPageIfNotEnoughVerticalResults);
|
||||||
}
|
}
|
||||||
|
|
3
interface/resources/qml/hifi/models/qmldir
Normal file
3
interface/resources/qml/hifi/models/qmldir
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module hifiModels
|
||||||
|
PSFListModel 1.0 PSFListModel.qml
|
||||||
|
S3Model 1.0 S3Model.qml
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
import "../simplifiedConstants" as SimplifiedConstants
|
import "../simplifiedConstants" as SimplifiedConstants
|
||||||
|
import "../simplifiedControls" as SimplifiedControls
|
||||||
import "./components" as AvatarAppComponents
|
import "./components" as AvatarAppComponents
|
||||||
import stylesUit 1.0 as HifiStylesUit
|
import stylesUit 1.0 as HifiStylesUit
|
||||||
import TabletScriptingInterface 1.0
|
import TabletScriptingInterface 1.0
|
||||||
|
@ -245,6 +246,10 @@ Rectangle {
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimplifiedControls.VerticalScrollBar {
|
||||||
|
parent: inventoryContentsList
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
import "../simplifiedConstants" as SimplifiedConstants
|
import "../simplifiedConstants" as SimplifiedConstants
|
||||||
|
import "../simplifiedControls" as SimplifiedControls
|
||||||
import stylesUit 1.0 as HifiStylesUit
|
import stylesUit 1.0 as HifiStylesUit
|
||||||
import "./audio" as AudioSettings
|
import "./audio" as AudioSettings
|
||||||
import "./general" as GeneralSettings
|
import "./general" as GeneralSettings
|
||||||
|
@ -129,9 +131,7 @@ Rectangle {
|
||||||
id: tabViewContainers
|
id: tabViewContainers
|
||||||
anchors.top: tabContainer.bottom
|
anchors.top: tabContainer.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 26
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 26
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,24 +162,20 @@ Rectangle {
|
||||||
visible: activeTabView === "devTabView"
|
visible: activeTabView === "devTabView"
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
SimplifiedControls.VerticalScrollBar {
|
||||||
source: {
|
parent: {
|
||||||
if (root.activeTabView === "generalTabView") {
|
if (activeTabView === "generalTabView") {
|
||||||
"images/accent1.svg"
|
generalTabViewContainer
|
||||||
} else if (root.activeTabView === "audioTabView") {
|
} else if (activeTabView === "audioTabView") {
|
||||||
"images/accent2.svg"
|
audioTabViewContainer
|
||||||
} else if (root.activeTabView === "vrTabView") {
|
} else if (activeTabView === "vrTabView") {
|
||||||
"images/accent3.svg"
|
vrTabViewContainer
|
||||||
} else {
|
} else if (activeTabView === "devTabView") {
|
||||||
"images/accent3.svg"
|
devTabViewContainer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: tabContainer.bottom
|
|
||||||
width: 106
|
|
||||||
height: 200
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@ Flickable {
|
||||||
id: root
|
id: root
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: audioColumnLayout.height
|
contentHeight: audioColumnLayout.height
|
||||||
topMargin: 24
|
|
||||||
bottomMargin: 24
|
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
function changePeakValuesEnabled(enabled) {
|
function changePeakValuesEnabled(enabled) {
|
||||||
|
@ -33,7 +31,7 @@ Flickable {
|
||||||
AudioScriptingInterface.devices.input.peakValuesEnabled = visible;
|
AudioScriptingInterface.devices.input.peakValuesEnabled = visible;
|
||||||
if (visible) {
|
if (visible) {
|
||||||
root.contentX = 0;
|
root.contentX = 0;
|
||||||
root.contentY = -root.topMargin;
|
root.contentY = 0;
|
||||||
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.connect(changePeakValuesEnabled);
|
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.connect(changePeakValuesEnabled);
|
||||||
} else {
|
} else {
|
||||||
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.disconnect(changePeakValuesEnabled);
|
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.disconnect(changePeakValuesEnabled);
|
||||||
|
@ -45,16 +43,35 @@ Flickable {
|
||||||
id: simplifiedUI
|
id: simplifiedUI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: accent
|
||||||
|
source: "../images/accent2.svg"
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 83
|
||||||
|
height: 156
|
||||||
|
transform: Scale {
|
||||||
|
xScale: -1
|
||||||
|
origin.x: accent.width / 2
|
||||||
|
origin.y: accent.height / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: audioColumnLayout
|
id: audioColumnLayout
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 26
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 26
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: volumeControlsContainer
|
id: volumeControlsContainer
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.topMargin: 24
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
HifiStylesUit.GraphikSemiBold {
|
HifiStylesUit.GraphikSemiBold {
|
||||||
|
@ -289,6 +306,7 @@ Flickable {
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: outputDeviceContainer
|
id: outputDeviceContainer
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.bottomMargin: 24
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
HifiStylesUit.GraphikSemiBold {
|
HifiStylesUit.GraphikSemiBold {
|
||||||
|
|
|
@ -19,14 +19,12 @@ Flickable {
|
||||||
id: root
|
id: root
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: devColumnLayout.height
|
contentHeight: devColumnLayout.height
|
||||||
topMargin: 24
|
|
||||||
bottomMargin: 24
|
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
root.contentX = 0;
|
root.contentX = 0;
|
||||||
root.contentY = -root.topMargin;
|
root.contentY = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,16 +33,36 @@ Flickable {
|
||||||
id: simplifiedUI
|
id: simplifiedUI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: accent
|
||||||
|
source: "../images/accent3.svg"
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 83
|
||||||
|
height: 156
|
||||||
|
transform: Scale {
|
||||||
|
xScale: -1
|
||||||
|
origin.x: accent.width / 2
|
||||||
|
origin.y: accent.height / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: devColumnLayout
|
id: devColumnLayout
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 26
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 26
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: uiControlsContainer
|
id: uiControlsContainer
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
HifiStylesUit.GraphikSemiBold {
|
HifiStylesUit.GraphikSemiBold {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
import "../../simplifiedConstants" as SimplifiedConstants
|
import "../../simplifiedConstants" as SimplifiedConstants
|
||||||
import "../../simplifiedControls" as SimplifiedControls
|
import "../../simplifiedControls" as SimplifiedControls
|
||||||
import stylesUit 1.0 as HifiStylesUit
|
import stylesUit 1.0 as HifiStylesUit
|
||||||
|
@ -20,8 +21,6 @@ Flickable {
|
||||||
id: root
|
id: root
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: generalColumnLayout.height
|
contentHeight: generalColumnLayout.height
|
||||||
topMargin: 24
|
|
||||||
bottomMargin: 24
|
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
onAvatarNametagModeChanged: {
|
onAvatarNametagModeChanged: {
|
||||||
|
@ -31,7 +30,7 @@ Flickable {
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
root.contentX = 0;
|
root.contentX = 0;
|
||||||
root.contentY = -root.topMargin;
|
root.contentY = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,16 +38,35 @@ Flickable {
|
||||||
id: simplifiedUI
|
id: simplifiedUI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: accent
|
||||||
|
source: "../images/accent1.svg"
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 83
|
||||||
|
height: 156
|
||||||
|
transform: Scale {
|
||||||
|
xScale: -1
|
||||||
|
origin.x: accent.width / 2
|
||||||
|
origin.y: accent.height / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: generalColumnLayout
|
id: generalColumnLayout
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 26
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 26
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: avatarNameTagsContainer
|
id: avatarNameTagsContainer
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.topMargin: 24
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
HifiStylesUit.GraphikSemiBold {
|
HifiStylesUit.GraphikSemiBold {
|
||||||
|
@ -193,29 +211,36 @@ Flickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiStylesUit.GraphikRegular {
|
ColumnLayout {
|
||||||
id: logoutText
|
id: logoutContainer
|
||||||
text: (AccountServices.username === "Unknown user" ? "Log In" : "Logout " + AccountServices.username)
|
Layout.preferredWidth: parent.width
|
||||||
wrapMode: Text.Wrap
|
Layout.bottomMargin: 24
|
||||||
width: paintedWidth
|
spacing: 0
|
||||||
height: paintedHeight
|
|
||||||
size: 14
|
|
||||||
color: simplifiedUI.colors.text.lightBlue
|
|
||||||
|
|
||||||
MouseArea {
|
HifiStylesUit.GraphikRegular {
|
||||||
anchors.fill: parent
|
id: logoutText
|
||||||
hoverEnabled: true
|
text: (AccountServices.username === "Unknown user" ? "Log In" : "Logout " + AccountServices.username)
|
||||||
onEntered: {
|
wrapMode: Text.Wrap
|
||||||
parent.color = simplifiedUI.colors.text.lightBlueHover;
|
width: paintedWidth
|
||||||
}
|
height: paintedHeight
|
||||||
onExited: {
|
size: 14
|
||||||
parent.color = simplifiedUI.colors.text.lightBlue;
|
color: simplifiedUI.colors.text.lightBlue
|
||||||
}
|
|
||||||
onClicked: {
|
MouseArea {
|
||||||
if (Account.loggedIn) {
|
anchors.fill: parent
|
||||||
AccountServices.logOut();
|
hoverEnabled: true
|
||||||
} else {
|
onEntered: {
|
||||||
DialogsManager.showLoginDialog();
|
parent.color = simplifiedUI.colors.text.lightBlueHover;
|
||||||
|
}
|
||||||
|
onExited: {
|
||||||
|
parent.color = simplifiedUI.colors.text.lightBlue;
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
if (Account.loggedIn) {
|
||||||
|
AccountServices.logOut();
|
||||||
|
} else {
|
||||||
|
DialogsManager.showLoginDialog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ Flickable {
|
||||||
id: root
|
id: root
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: vrColumnLayout.height
|
contentHeight: vrColumnLayout.height
|
||||||
topMargin: 24
|
|
||||||
bottomMargin: 24
|
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
function changePeakValuesEnabled(enabled) {
|
function changePeakValuesEnabled(enabled) {
|
||||||
|
@ -33,7 +31,7 @@ Flickable {
|
||||||
AudioScriptingInterface.devices.input.peakValuesEnabled = visible;
|
AudioScriptingInterface.devices.input.peakValuesEnabled = visible;
|
||||||
if (visible) {
|
if (visible) {
|
||||||
root.contentX = 0;
|
root.contentX = 0;
|
||||||
root.contentY = -root.topMargin;
|
root.contentY = 0;
|
||||||
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.connect(changePeakValuesEnabled);
|
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.connect(changePeakValuesEnabled);
|
||||||
} else {
|
} else {
|
||||||
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.disconnect(changePeakValuesEnabled);
|
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.disconnect(changePeakValuesEnabled);
|
||||||
|
@ -45,16 +43,35 @@ Flickable {
|
||||||
id: simplifiedUI
|
id: simplifiedUI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: accent
|
||||||
|
source: "../images/accent3.svg"
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 83
|
||||||
|
height: 156
|
||||||
|
transform: Scale {
|
||||||
|
xScale: -1
|
||||||
|
origin.x: accent.width / 2
|
||||||
|
origin.y: accent.height / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: vrColumnLayout
|
id: vrColumnLayout
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 26
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 26
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: controlsContainer
|
id: controlsContainer
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.topMargin: 24
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
HifiStylesUit.GraphikSemiBold {
|
HifiStylesUit.GraphikSemiBold {
|
||||||
|
@ -278,6 +295,7 @@ Flickable {
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: outputDeviceContainer
|
id: outputDeviceContainer
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.bottomMargin: 24
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
HifiStylesUit.GraphikSemiBold {
|
HifiStylesUit.GraphikSemiBold {
|
||||||
|
|
|
@ -144,6 +144,10 @@ QtObject {
|
||||||
readonly property color hover: "#FFFFFF"
|
readonly property color hover: "#FFFFFF"
|
||||||
readonly property color focus: "#FFFFFF"
|
readonly property color focus: "#FFFFFF"
|
||||||
}
|
}
|
||||||
|
readonly property QtObject scrollBar: QtObject {
|
||||||
|
readonly property color background: "#474747"
|
||||||
|
readonly property color contentItem: "#0198CB"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property color darkSeparator: "#595959"
|
readonly property color darkSeparator: "#595959"
|
||||||
|
@ -219,6 +223,10 @@ QtObject {
|
||||||
readonly property QtObject textField: QtObject {
|
readonly property QtObject textField: QtObject {
|
||||||
readonly property int editPencilPadding: 6
|
readonly property int editPencilPadding: 6
|
||||||
}
|
}
|
||||||
|
readonly property QtObject scrollBar: QtObject {
|
||||||
|
readonly property int backgroundWidth: 9
|
||||||
|
readonly property int contentItemWidth: 7
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// VerticalScrollBar.qml
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2019-06-17
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
import QtQuick 2.10
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import "../simplifiedConstants" as SimplifiedConstants
|
||||||
|
|
||||||
|
ScrollBar {
|
||||||
|
SimplifiedConstants.SimplifiedConstants {
|
||||||
|
id: simplifiedUI
|
||||||
|
}
|
||||||
|
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
policy: ScrollBar.AlwaysOn
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 4
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 4
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 4
|
||||||
|
width: simplifiedUI.sizes.controls.scrollBar.backgroundWidth
|
||||||
|
visible: parent.contentHeight > parent.parent.height
|
||||||
|
position: parent.contentY / parent.contentHeight
|
||||||
|
size: parent.parent.height / parent.contentHeight
|
||||||
|
minimumSize: 0.1
|
||||||
|
background: Rectangle {
|
||||||
|
color: simplifiedUI.colors.controls.scrollBar.background
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
contentItem: Rectangle {
|
||||||
|
width: simplifiedUI.sizes.controls.scrollBar.contentItemWidth
|
||||||
|
color: simplifiedUI.colors.controls.scrollBar.contentItem
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
topMargin: 1
|
||||||
|
bottomMargin: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onPositionChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
parent.contentY = position * parent.contentHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -435,7 +435,7 @@ DetailedMotionState* AvatarManager::createDetailedMotionState(OtherAvatarPointer
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarManager::rebuildAvatarPhysics(PhysicsEngine::Transaction& transaction, OtherAvatarPointer avatar) {
|
void AvatarManager::rebuildAvatarPhysics(PhysicsEngine::Transaction& transaction, const OtherAvatarPointer& avatar) {
|
||||||
if (!avatar->_motionState) {
|
if (!avatar->_motionState) {
|
||||||
avatar->_motionState = new AvatarMotionState(avatar, nullptr);
|
avatar->_motionState = new AvatarMotionState(avatar, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -452,20 +452,24 @@ void AvatarManager::rebuildAvatarPhysics(PhysicsEngine::Transaction& transaction
|
||||||
transaction.objectsToAdd.push_back(motionState);
|
transaction.objectsToAdd.push_back(motionState);
|
||||||
}
|
}
|
||||||
motionState->clearIncomingDirtyFlags();
|
motionState->clearIncomingDirtyFlags();
|
||||||
|
}
|
||||||
|
|
||||||
// Rather than reconcile numbers of joints after change to model or LOD
|
void AvatarManager::removeDetailedAvatarPhysics(PhysicsEngine::Transaction& transaction, const OtherAvatarPointer& avatar) {
|
||||||
// we blow away old detailedMotionStates and create anew all around.
|
|
||||||
|
|
||||||
// delete old detailedMotionStates
|
// delete old detailedMotionStates
|
||||||
auto& detailedMotionStates = avatar->getDetailedMotionStates();
|
auto& detailedMotionStates = avatar->getDetailedMotionStates();
|
||||||
if (detailedMotionStates.size() != 0) {
|
if (detailedMotionStates.size() != 0) {
|
||||||
for (auto& detailedMotionState : detailedMotionStates) {
|
for (auto& detailedMotionState : detailedMotionStates) {
|
||||||
transaction.objectsToRemove.push_back(detailedMotionState);
|
transaction.objectsToRemove.push_back(detailedMotionState);
|
||||||
}
|
}
|
||||||
avatar->resetDetailedMotionStates();
|
avatar->forgetDetailedMotionStates();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// build new detailedMotionStates
|
void AvatarManager::rebuildDetailedAvatarPhysics(PhysicsEngine::Transaction& transaction, const OtherAvatarPointer& avatar) {
|
||||||
|
// Rather than reconcile numbers of joints after change to model or LOD
|
||||||
|
// we blow away old detailedMotionStates and create anew all around.
|
||||||
|
removeDetailedAvatarPhysics(transaction, avatar);
|
||||||
|
auto& detailedMotionStates = avatar->getDetailedMotionStates();
|
||||||
OtherAvatar::BodyLOD lod = avatar->getBodyLOD();
|
OtherAvatar::BodyLOD lod = avatar->getBodyLOD();
|
||||||
if (lod == OtherAvatar::BodyLOD::Sphere) {
|
if (lod == OtherAvatar::BodyLOD::Sphere) {
|
||||||
auto dMotionState = createDetailedMotionState(avatar, -1);
|
auto dMotionState = createDetailedMotionState(avatar, -1);
|
||||||
|
@ -483,24 +487,21 @@ void AvatarManager::rebuildAvatarPhysics(PhysicsEngine::Transaction& transaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
avatar->_needsReinsertion = false;
|
avatar->_needsDetailedRebuild = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
|
void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
|
||||||
_myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
|
_myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
|
||||||
for (auto avatar : _otherAvatarsToChangeInPhysics) {
|
for (auto avatar : _otherAvatarsToChangeInPhysics) {
|
||||||
bool isInPhysics = avatar->isInPhysicsSimulation();
|
bool isInPhysics = avatar->isInPhysicsSimulation();
|
||||||
if (isInPhysics != avatar->shouldBeInPhysicsSimulation() || avatar->_needsReinsertion) {
|
if (isInPhysics != avatar->shouldBeInPhysicsSimulation()) {
|
||||||
if (isInPhysics) {
|
if (isInPhysics) {
|
||||||
transaction.objectsToRemove.push_back(avatar->_motionState);
|
transaction.objectsToRemove.push_back(avatar->_motionState);
|
||||||
avatar->_motionState = nullptr;
|
avatar->_motionState = nullptr;
|
||||||
auto& detailedMotionStates = avatar->getDetailedMotionStates();
|
removeDetailedAvatarPhysics(transaction, avatar);
|
||||||
for (auto& motionState : detailedMotionStates) {
|
|
||||||
transaction.objectsToRemove.push_back(motionState);
|
|
||||||
}
|
|
||||||
avatar->resetDetailedMotionStates();
|
|
||||||
} else {
|
} else {
|
||||||
rebuildAvatarPhysics(transaction, avatar);
|
rebuildAvatarPhysics(transaction, avatar);
|
||||||
|
rebuildDetailedAvatarPhysics(transaction, avatar);
|
||||||
}
|
}
|
||||||
} else if (isInPhysics) {
|
} else if (isInPhysics) {
|
||||||
AvatarMotionState* motionState = avatar->_motionState;
|
AvatarMotionState* motionState = avatar->_motionState;
|
||||||
|
@ -519,6 +520,10 @@ void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transact
|
||||||
}
|
}
|
||||||
motionState->clearIncomingDirtyFlags();
|
motionState->clearIncomingDirtyFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (avatar->_needsDetailedRebuild) {
|
||||||
|
rebuildDetailedAvatarPhysics(transaction, avatar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_otherAvatarsToChangeInPhysics.clear();
|
_otherAvatarsToChangeInPhysics.clear();
|
||||||
|
|
|
@ -274,7 +274,9 @@ public slots:
|
||||||
protected:
|
protected:
|
||||||
AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) override;
|
AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) override;
|
||||||
DetailedMotionState* createDetailedMotionState(OtherAvatarPointer avatar, int32_t jointIndex);
|
DetailedMotionState* createDetailedMotionState(OtherAvatarPointer avatar, int32_t jointIndex);
|
||||||
void rebuildAvatarPhysics(PhysicsEngine::Transaction& transaction, OtherAvatarPointer avatar);
|
void rebuildAvatarPhysics(PhysicsEngine::Transaction& transaction, const OtherAvatarPointer& avatar);
|
||||||
|
void removeDetailedAvatarPhysics(PhysicsEngine::Transaction& transaction, const OtherAvatarPointer& avatar);
|
||||||
|
void rebuildDetailedAvatarPhysics(PhysicsEngine::Transaction& transaction, const OtherAvatarPointer& avatar);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit AvatarManager(QObject* parent = 0);
|
explicit AvatarManager(QObject* parent = 0);
|
||||||
|
|
|
@ -1416,6 +1416,10 @@ void MyAvatar::setEnableDebugDrawAnimPose(bool isEnabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setDebugDrawAnimPoseName(QString poseName) {
|
||||||
|
_debugDrawAnimPoseName.set(poseName);
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) {
|
void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
const glm::vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
|
const glm::vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
@ -3086,15 +3090,26 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_enableDebugDrawAnimPose && animSkeleton) {
|
if (_enableDebugDrawAnimPose && animSkeleton) {
|
||||||
// build absolute AnimPoseVec from rig
|
|
||||||
AnimPoseVec absPoses;
|
AnimPoseVec absPoses;
|
||||||
const Rig& rig = _skeletonModel->getRig();
|
const Rig& rig = _skeletonModel->getRig();
|
||||||
absPoses.reserve(rig.getJointStateCount());
|
const glm::vec4 CYAN(0.1f, 0.6f, 0.6f, 1.0f);
|
||||||
for (int i = 0; i < rig.getJointStateCount(); i++) {
|
|
||||||
absPoses.push_back(AnimPose(rig.getJointTransform(i)));
|
QString name = _debugDrawAnimPoseName.get();
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
// build absolute AnimPoseVec from rig transforms. i.e. the same that are used for rendering.
|
||||||
|
absPoses.reserve(rig.getJointStateCount());
|
||||||
|
for (int i = 0; i < rig.getJointStateCount(); i++) {
|
||||||
|
absPoses.push_back(AnimPose(rig.getJointTransform(i)));
|
||||||
|
}
|
||||||
|
AnimDebugDraw::getInstance().addAbsolutePoses("myAvatarAnimPoses", animSkeleton, absPoses, xform, CYAN);
|
||||||
|
} else {
|
||||||
|
AnimNode::ConstPointer node = rig.findAnimNodeByName(name);
|
||||||
|
if (node) {
|
||||||
|
rig.buildAbsoluteRigPoses(node->getPoses(), absPoses);
|
||||||
|
AnimDebugDraw::getInstance().addAbsolutePoses("myAvatarAnimPoses", animSkeleton, absPoses, xform, CYAN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glm::vec4 cyan(0.1f, 0.6f, 0.6f, 1.0f);
|
|
||||||
AnimDebugDraw::getInstance().addAbsolutePoses("myAvatarAnimPoses", animSkeleton, absPoses, xform, cyan);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2018,12 +2018,20 @@ public slots:
|
||||||
void setEnableDebugDrawDefaultPose(bool isEnabled);
|
void setEnableDebugDrawDefaultPose(bool isEnabled);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Displays animation debug graphics.
|
* Displays animation debug graphics. By default it shows the animation poses used for rendering.
|
||||||
|
* However, the property MyAvatar.setDebugDrawAnimPoseName can be used to draw a specific animation node.
|
||||||
* @function MyAvatar.setEnableDebugDrawAnimPose
|
* @function MyAvatar.setEnableDebugDrawAnimPose
|
||||||
* @param {boolean} enabled - <code>true</code> to show the debug graphics, <code>false</code> to hide.
|
* @param {boolean} enabled - <code>true</code> to show the debug graphics, <code>false</code> to hide.
|
||||||
*/
|
*/
|
||||||
void setEnableDebugDrawAnimPose(bool isEnabled);
|
void setEnableDebugDrawAnimPose(bool isEnabled);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* If set it determines which animation debug graphics to draw, when MyAvatar.setEnableDebugDrawAnimPose is set to true.
|
||||||
|
* @function MyAvatar.setDebugDrawAnimPoseName
|
||||||
|
* @param {boolean} enabled - <code>true</code> to show the debug graphics, <code>false</code> to hide.
|
||||||
|
*/
|
||||||
|
void setDebugDrawAnimPoseName(QString poseName);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Displays position debug graphics.
|
* Displays position debug graphics.
|
||||||
* @function MyAvatar.setEnableDebugDrawPosition
|
* @function MyAvatar.setEnableDebugDrawPosition
|
||||||
|
@ -2666,6 +2674,8 @@ private:
|
||||||
bool _enableDebugDrawIKChains { false };
|
bool _enableDebugDrawIKChains { false };
|
||||||
bool _enableDebugDrawDetailedCollision { false };
|
bool _enableDebugDrawDetailedCollision { false };
|
||||||
|
|
||||||
|
ThreadSafeValueCache<QString> _debugDrawAnimPoseName;
|
||||||
|
|
||||||
mutable bool _cauterizationNeedsUpdate { false }; // do we need to scan children and update their "cauterized" state?
|
mutable bool _cauterizationNeedsUpdate { false }; // do we need to scan children and update their "cauterized" state?
|
||||||
|
|
||||||
AudioListenerMode _audioListenerMode;
|
AudioListenerMode _audioListenerMode;
|
||||||
|
|
|
@ -398,15 +398,13 @@ DetailedMotionState* MyCharacterController::createDetailedMotionStateForJoint(in
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyCharacterController::clearDetailedMotionStates() {
|
void MyCharacterController::clearDetailedMotionStates() {
|
||||||
|
// we don't actually clear the MotionStates here
|
||||||
|
// instead we twiddle some flags as a signal of what to do later
|
||||||
_pendingFlags |= PENDING_FLAG_REMOVE_DETAILED_FROM_SIMULATION;
|
_pendingFlags |= PENDING_FLAG_REMOVE_DETAILED_FROM_SIMULATION;
|
||||||
// We make sure we don't add them again
|
// We make sure we don't add them again
|
||||||
_pendingFlags &= ~PENDING_FLAG_ADD_DETAILED_TO_SIMULATION;
|
_pendingFlags &= ~PENDING_FLAG_ADD_DETAILED_TO_SIMULATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyCharacterController::resetDetailedMotionStates() {
|
|
||||||
_detailedMotionStates.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyCharacterController::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
|
void MyCharacterController::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
|
||||||
for (size_t i = 0; i < _detailedMotionStates.size(); i++) {
|
for (size_t i = 0; i < _detailedMotionStates.size(); i++) {
|
||||||
_detailedMotionStates[i]->forceActive();
|
_detailedMotionStates[i]->forceActive();
|
||||||
|
@ -416,6 +414,8 @@ void MyCharacterController::buildPhysicsTransaction(PhysicsEngine::Transaction&
|
||||||
for (size_t i = 0; i < _detailedMotionStates.size(); i++) {
|
for (size_t i = 0; i < _detailedMotionStates.size(); i++) {
|
||||||
transaction.objectsToRemove.push_back(_detailedMotionStates[i]);
|
transaction.objectsToRemove.push_back(_detailedMotionStates[i]);
|
||||||
}
|
}
|
||||||
|
// NOTE: the DetailedMotionStates are deleted after being added to PhysicsEngine::Transaction::_objectsToRemove
|
||||||
|
// See AvatarManager::handleProcessedPhysicsTransaction()
|
||||||
_detailedMotionStates.clear();
|
_detailedMotionStates.clear();
|
||||||
}
|
}
|
||||||
if (_pendingFlags & PENDING_FLAG_ADD_DETAILED_TO_SIMULATION) {
|
if (_pendingFlags & PENDING_FLAG_ADD_DETAILED_TO_SIMULATION) {
|
||||||
|
|
|
@ -48,7 +48,6 @@ public:
|
||||||
DetailedMotionState* createDetailedMotionStateForJoint(int32_t jointIndex);
|
DetailedMotionState* createDetailedMotionStateForJoint(int32_t jointIndex);
|
||||||
std::vector<DetailedMotionState*>& getDetailedMotionStates() { return _detailedMotionStates; }
|
std::vector<DetailedMotionState*>& getDetailedMotionStates() { return _detailedMotionStates; }
|
||||||
void clearDetailedMotionStates();
|
void clearDetailedMotionStates();
|
||||||
void resetDetailedMotionStates();
|
|
||||||
|
|
||||||
void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction);
|
void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction);
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ const btCollisionShape* OtherAvatar::createCollisionShape(int32_t jointIndex, bo
|
||||||
return ObjectMotionState::getShapeManager()->getShape(shapeInfo);
|
return ObjectMotionState::getShapeManager()->getShape(shapeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OtherAvatar::resetDetailedMotionStates() {
|
void OtherAvatar::forgetDetailedMotionStates() {
|
||||||
// NOTE: the DetailedMotionStates are deleted after being added to PhysicsEngine::Transaction::_objectsToRemove
|
// NOTE: the DetailedMotionStates are deleted after being added to PhysicsEngine::Transaction::_objectsToRemove
|
||||||
// See AvatarManager::handleProcessedPhysicsTransaction()
|
// See AvatarManager::handleProcessedPhysicsTransaction()
|
||||||
_detailedMotionStates.clear();
|
_detailedMotionStates.clear();
|
||||||
|
@ -209,7 +209,7 @@ void OtherAvatar::computeShapeLOD() {
|
||||||
if (newLOD != _bodyLOD) {
|
if (newLOD != _bodyLOD) {
|
||||||
_bodyLOD = newLOD;
|
_bodyLOD = newLOD;
|
||||||
if (isInPhysicsSimulation()) {
|
if (isInPhysicsSimulation()) {
|
||||||
_needsReinsertion = true;
|
_needsDetailedRebuild = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,14 +224,14 @@ bool OtherAvatar::shouldBeInPhysicsSimulation() const {
|
||||||
|
|
||||||
bool OtherAvatar::needsPhysicsUpdate() const {
|
bool OtherAvatar::needsPhysicsUpdate() const {
|
||||||
constexpr uint32_t FLAGS_OF_INTEREST = Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS | Simulation::DIRTY_POSITION | Simulation::DIRTY_COLLISION_GROUP;
|
constexpr uint32_t FLAGS_OF_INTEREST = Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS | Simulation::DIRTY_POSITION | Simulation::DIRTY_COLLISION_GROUP;
|
||||||
return (_needsReinsertion || (_motionState && (bool)(_motionState->getIncomingDirtyFlags() & FLAGS_OF_INTEREST)));
|
return (_needsDetailedRebuild || (_motionState && (bool)(_motionState->getIncomingDirtyFlags() & FLAGS_OF_INTEREST)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OtherAvatar::rebuildCollisionShape() {
|
void OtherAvatar::rebuildCollisionShape() {
|
||||||
if (_motionState) {
|
if (_motionState) {
|
||||||
// do not actually rebuild here, instead flag for later
|
// do not actually rebuild here, instead flag for later
|
||||||
_motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
_motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||||
_needsReinsertion = true;
|
_needsDetailedRebuild = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
|
|
||||||
const btCollisionShape* createCollisionShape(int32_t jointIndex, bool& isBound, std::vector<int32_t>& boundJoints);
|
const btCollisionShape* createCollisionShape(int32_t jointIndex, bool& isBound, std::vector<int32_t>& boundJoints);
|
||||||
std::vector<DetailedMotionState*>& getDetailedMotionStates() { return _detailedMotionStates; }
|
std::vector<DetailedMotionState*>& getDetailedMotionStates() { return _detailedMotionStates; }
|
||||||
void resetDetailedMotionStates();
|
void forgetDetailedMotionStates();
|
||||||
BodyLOD getBodyLOD() { return _bodyLOD; }
|
BodyLOD getBodyLOD() { return _bodyLOD; }
|
||||||
void computeShapeLOD();
|
void computeShapeLOD();
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ protected:
|
||||||
int32_t _spaceIndex { -1 };
|
int32_t _spaceIndex { -1 };
|
||||||
uint8_t _workloadRegion { workload::Region::INVALID };
|
uint8_t _workloadRegion { workload::Region::INVALID };
|
||||||
BodyLOD _bodyLOD { BodyLOD::Sphere };
|
BodyLOD _bodyLOD { BodyLOD::Sphere };
|
||||||
bool _needsReinsertion { false };
|
bool _needsDetailedRebuild { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
using OtherAvatarPointer = std::shared_ptr<OtherAvatar>;
|
using OtherAvatarPointer = std::shared_ptr<OtherAvatar>;
|
||||||
|
|
|
@ -64,7 +64,8 @@ function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files})
|
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files})
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME})
|
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME}
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME})
|
||||||
set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "")
|
set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "")
|
||||||
if (LAUNCHER_HMAC_SECRET STREQUAL "")
|
if (LAUNCHER_HMAC_SECRET STREQUAL "")
|
||||||
message(FATAL_ERROR "LAUNCHER_HMAC_SECRET is not set")
|
message(FATAL_ERROR "LAUNCHER_HMAC_SECRET is not set")
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
<string>${APP_NAME}</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
@ -29,7 +29,9 @@
|
||||||
<string>Window</string>
|
<string>Window</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>HQ Launcher</string>
|
<string>CFBundleName</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
break;
|
break;
|
||||||
case CHECKING_UPDATE:
|
case CHECKING_UPDATE:
|
||||||
[self.boldStatus setStringValue:@"Getting updates..."];
|
[self.boldStatus setStringValue:@"Getting updates..."];
|
||||||
[self.smallStatus setStringValue:@"We're getting the lastest and greatest for you, one sec."];
|
[self.smallStatus setStringValue:@"We're getting the latest and greatest for you, one sec."];
|
||||||
break;
|
break;
|
||||||
case RUNNING_INTERFACE_AFTER_UPDATE:
|
case RUNNING_INTERFACE_AFTER_UPDATE:
|
||||||
[self.boldStatus setStringValue:@"You're good to go!"];
|
[self.boldStatus setStringValue:@"You're good to go!"];
|
||||||
|
|
|
@ -10,10 +10,13 @@
|
||||||
|
|
||||||
#include "AnimClip.h"
|
#include "AnimClip.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "GLMHelpers.h"
|
#include "GLMHelpers.h"
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
|
||||||
AnimClip::AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag) :
|
AnimClip::AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag) :
|
||||||
AnimNode(AnimNode::Type::Clip, id),
|
AnimNode(AnimNode::Type::Clip, id),
|
||||||
_startFrame(startFrame),
|
_startFrame(startFrame),
|
||||||
|
@ -107,6 +110,19 @@ static std::vector<int> buildJointIndexMap(const AnimSkeleton& dstSkeleton, cons
|
||||||
return jointIndexMap;
|
return jointIndexMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_CUSTOM_ASSERT
|
||||||
|
#undef ASSERT
|
||||||
|
#define ASSERT(x) \
|
||||||
|
do { \
|
||||||
|
if (!(x)) { \
|
||||||
|
int* bad_ptr = 0; \
|
||||||
|
*bad_ptr = 0x0badf00d; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define ASSERT assert
|
||||||
|
#endif
|
||||||
|
|
||||||
void AnimClip::copyFromNetworkAnim() {
|
void AnimClip::copyFromNetworkAnim() {
|
||||||
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
||||||
_anim.clear();
|
_anim.clear();
|
||||||
|
@ -165,11 +181,14 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
|
|
||||||
for (int frame = 0; frame < animFrameCount; frame++) {
|
for (int frame = 0; frame < animFrameCount; frame++) {
|
||||||
const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
|
const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
|
||||||
|
ASSERT(frame >= 0 && frame < (int)animModel.animationFrames.size());
|
||||||
|
|
||||||
// extract the full rotations from the animFrame (including pre and post rotations from the animModel).
|
// extract the full rotations from the animFrame (including pre and post rotations from the animModel).
|
||||||
std::vector<glm::quat> animRotations;
|
std::vector<glm::quat> animRotations;
|
||||||
animRotations.reserve(animJointCount);
|
animRotations.reserve(animJointCount);
|
||||||
for (int i = 0; i < animJointCount; i++) {
|
for (int i = 0; i < animJointCount; i++) {
|
||||||
|
ASSERT(i >= 0 && i < (int)animModel.joints.size());
|
||||||
|
ASSERT(i >= 0 && i < (int)animFrame.rotations.size());
|
||||||
animRotations.push_back(animModel.joints[i].preRotation * animFrame.rotations[i] * animModel.joints[i].postRotation);
|
animRotations.push_back(animModel.joints[i].preRotation * animFrame.rotations[i] * animModel.joints[i].postRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,10 +199,12 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
std::vector<glm::quat> avatarRotations;
|
std::vector<glm::quat> avatarRotations;
|
||||||
avatarRotations.reserve(avatarJointCount);
|
avatarRotations.reserve(avatarJointCount);
|
||||||
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||||
|
ASSERT(avatarJointIndex >= 0 && avatarJointIndex < (int)avatarToAnimJointIndexMap.size());
|
||||||
int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex];
|
int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex];
|
||||||
if (animJointIndex >= 0) {
|
if (animJointIndex >= 0) {
|
||||||
// This joint is in both animation and avatar.
|
// This joint is in both animation and avatar.
|
||||||
// Set the absolute rotation directly
|
// Set the absolute rotation directly
|
||||||
|
ASSERT(animJointIndex >= 0 && animJointIndex < (int)animRotations.size());
|
||||||
avatarRotations.push_back(animRotations[animJointIndex]);
|
avatarRotations.push_back(animRotations[animJointIndex]);
|
||||||
} else {
|
} else {
|
||||||
// This joint is NOT in the animation at all.
|
// This joint is NOT in the animation at all.
|
||||||
|
@ -192,6 +213,7 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
glm::quat avatarParentAbsoluteRot;
|
glm::quat avatarParentAbsoluteRot;
|
||||||
int avatarParentJointIndex = avatarSkeleton->getParentIndex(avatarJointIndex);
|
int avatarParentJointIndex = avatarSkeleton->getParentIndex(avatarJointIndex);
|
||||||
if (avatarParentJointIndex >= 0) {
|
if (avatarParentJointIndex >= 0) {
|
||||||
|
ASSERT(avatarParentJointIndex >= 0 && avatarParentJointIndex < (int)avatarRotations.size());
|
||||||
avatarParentAbsoluteRot = avatarRotations[avatarParentJointIndex];
|
avatarParentAbsoluteRot = avatarRotations[avatarParentJointIndex];
|
||||||
}
|
}
|
||||||
avatarRotations.push_back(avatarParentAbsoluteRot * avatarRelativeDefaultRot);
|
avatarRotations.push_back(avatarParentAbsoluteRot * avatarRelativeDefaultRot);
|
||||||
|
@ -201,6 +223,7 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
// convert avatar rotations into relative frame
|
// convert avatar rotations into relative frame
|
||||||
avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations);
|
avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations);
|
||||||
|
|
||||||
|
ASSERT(frame >= 0 && frame < (int)_anim.size());
|
||||||
_anim[frame].reserve(avatarJointCount);
|
_anim[frame].reserve(avatarJointCount);
|
||||||
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||||
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
||||||
|
@ -209,12 +232,15 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
glm::vec3 relativeScale = avatarDefaultPose.scale();
|
glm::vec3 relativeScale = avatarDefaultPose.scale();
|
||||||
|
|
||||||
glm::vec3 relativeTranslation;
|
glm::vec3 relativeTranslation;
|
||||||
|
ASSERT(avatarJointIndex >= 0 && avatarJointIndex < (int)avatarToAnimJointIndexMap.size());
|
||||||
int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex];
|
int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex];
|
||||||
if (animJointIndex >= 0) {
|
if (animJointIndex >= 0) {
|
||||||
// This joint is in both animation and avatar.
|
// This joint is in both animation and avatar.
|
||||||
|
ASSERT(animJointIndex >= 0 && animJointIndex < (int)animFrame.translations.size());
|
||||||
const glm::vec3& animTrans = animFrame.translations[animJointIndex];
|
const glm::vec3& animTrans = animFrame.translations[animJointIndex];
|
||||||
|
|
||||||
// retarget translation from animation to avatar
|
// retarget translation from animation to avatar
|
||||||
|
ASSERT(animJointIndex >= 0 && animJointIndex < (int)animModel.animationFrames[0].translations.size());
|
||||||
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
|
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
|
||||||
relativeTranslation = avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans);
|
relativeTranslation = avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans);
|
||||||
} else {
|
} else {
|
||||||
|
@ -224,6 +250,7 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the final pose
|
// build the final pose
|
||||||
|
ASSERT(avatarJointIndex >= 0 && avatarJointIndex < (int)avatarRotations.size());
|
||||||
_anim[frame].push_back(AnimPose(relativeScale, avatarRotations[avatarJointIndex], relativeTranslation));
|
_anim[frame].push_back(AnimPose(relativeScale, avatarRotations[avatarJointIndex], relativeTranslation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,8 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AnimPoseVec& getPoses() const { return getPosesInternal(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void setCurrentFrameInternal(float frame) {}
|
virtual void setCurrentFrameInternal(float frame) {}
|
||||||
|
|
|
@ -2232,6 +2232,14 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimNode::ConstPointer Rig::findAnimNodeByName(const QString& name) const {
|
||||||
|
if (_animNode) {
|
||||||
|
return _animNode->findByName(name);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const {
|
bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const {
|
||||||
if (_animSkeleton && _rootJointIndex >= 0) {
|
if (_animSkeleton && _rootJointIndex >= 0) {
|
||||||
modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteDefaultPose(_rootJointIndex).trans();
|
modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteDefaultPose(_rootJointIndex).trans();
|
||||||
|
@ -2258,7 +2266,7 @@ void Rig::applyOverridePoses() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) {
|
void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) const {
|
||||||
DETAILED_PERFORMANCE_TIMER("buildAbsolute");
|
DETAILED_PERFORMANCE_TIMER("buildAbsolute");
|
||||||
if (!_animSkeleton) {
|
if (!_animSkeleton) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -196,6 +196,7 @@ public:
|
||||||
void initAnimGraph(const QUrl& url);
|
void initAnimGraph(const QUrl& url);
|
||||||
|
|
||||||
AnimNode::ConstPointer getAnimNode() const { return _animNode; }
|
AnimNode::ConstPointer getAnimNode() const { return _animNode; }
|
||||||
|
AnimNode::ConstPointer findAnimNodeByName(const QString& name) const;
|
||||||
AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; }
|
AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; }
|
||||||
QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
|
QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
|
||||||
void removeAnimationStateHandler(QScriptValue handler);
|
void removeAnimationStateHandler(QScriptValue handler);
|
||||||
|
@ -243,7 +244,7 @@ public:
|
||||||
Flow& getFlow() { return _internalFlow; }
|
Flow& getFlow() { return _internalFlow; }
|
||||||
|
|
||||||
float getUnscaledEyeHeight() const;
|
float getUnscaledEyeHeight() const;
|
||||||
|
void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void onLoadComplete();
|
void onLoadComplete();
|
||||||
|
@ -252,7 +253,6 @@ protected:
|
||||||
bool isIndexValid(int index) const { return _animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints(); }
|
bool isIndexValid(int index) const { return _animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints(); }
|
||||||
void updateAnimationStateHandlers();
|
void updateAnimationStateHandlers();
|
||||||
void applyOverridePoses();
|
void applyOverridePoses();
|
||||||
void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut);
|
|
||||||
|
|
||||||
void updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headMatrix);
|
void updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headMatrix);
|
||||||
void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated,
|
void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated,
|
||||||
|
|
|
@ -368,6 +368,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == SHAPE_TYPE_COMPOUND) {
|
if (type == SHAPE_TYPE_COMPOUND) {
|
||||||
|
if (!_compoundShapeResource || !_compoundShapeResource->isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateModelBounds();
|
updateModelBounds();
|
||||||
|
|
||||||
// should never fall in here when collision model not fully loaded
|
// should never fall in here when collision model not fully loaded
|
||||||
|
|
|
@ -152,7 +152,7 @@ function simplifiedStatusIndicator(properties) {
|
||||||
|
|
||||||
|
|
||||||
// When avatar goes away, set status to busy
|
// When avatar goes away, set status to busy
|
||||||
var previousStatus;
|
var previousStatus = "available";
|
||||||
function onWentAway() {
|
function onWentAway() {
|
||||||
previousStatus = currentStatus;
|
previousStatus = currentStatus;
|
||||||
if (currentStatus !== "busy") {
|
if (currentStatus !== "busy") {
|
||||||
|
|
Loading…
Reference in a new issue