mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 14:12:50 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into blackProp
This commit is contained in:
commit
206bc0addb
37 changed files with 491 additions and 381 deletions
BIN
interface/resources/fonts/rawline-500.ttf
Normal file
BIN
interface/resources/fonts/rawline-500.ttf
Normal file
Binary file not shown.
|
@ -6,7 +6,7 @@ import QtQuick.Layouts 1.3
|
|||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "."
|
||||
import stylesUit 1.0
|
||||
import stylesUit 1.0 as HifiStylesUit
|
||||
import "../audio" as HifiAudio
|
||||
|
||||
Item {
|
||||
|
@ -49,44 +49,116 @@ Item {
|
|||
}
|
||||
|
||||
Item {
|
||||
width: 150
|
||||
height: 50
|
||||
id: rightContainer
|
||||
width: clockItem.width > loginItem.width ? clockItem.width + clockAmPmTextMetrics.width :
|
||||
loginItem.width + clockAmPmTextMetrics.width
|
||||
height: parent.height
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 15
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: 20
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
function timeChanged() {
|
||||
var date = new Date();
|
||||
clockTime.text = date.toLocaleTimeString(Qt.locale("en_US"), "h:mm ap");
|
||||
var regex = /[\sa-zA-z]+/;
|
||||
clockTime.text = clockTime.text.replace(regex, "");
|
||||
clockAmPm.text = date.toLocaleTimeString(Qt.locale("en_US"), "ap");
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
|
||||
horizontalAlignment: Text.AlignRight
|
||||
Layout.alignment: Qt.AlignRight
|
||||
font.pixelSize: 20
|
||||
color: "#afafaf"
|
||||
Timer {
|
||||
interval: 1000; running: true; repeat: true;
|
||||
onTriggered: rightContainer.timeChanged();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: clockAmPmItem
|
||||
width: clockAmPmTextMetrics.width
|
||||
height: clockAmPmTextMetrics.height
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
TextMetrics {
|
||||
id: clockAmPmTextMetrics
|
||||
text: clockAmPm.text
|
||||
font: clockAmPm.font
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
visible: Account.loggedIn
|
||||
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
|
||||
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
|
||||
horizontalAlignment: Text.AlignRight
|
||||
Layout.alignment: Qt.AlignRight
|
||||
font.pixelSize: 20
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
id: clockAmPm
|
||||
anchors.right: parent.right
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.pixelSize: 12
|
||||
font.family: "Rawline"
|
||||
color: "#afafaf"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (!Account.loggedIn) {
|
||||
DialogsManager.showLoginDialog()
|
||||
} else {
|
||||
Account.logOut()
|
||||
Item {
|
||||
id: clockItem
|
||||
width: clockTimeTextMetrics.width
|
||||
height: clockTimeTextMetrics.height
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: -10
|
||||
right: clockAmPmItem.left
|
||||
rightMargin: 5
|
||||
}
|
||||
TextMetrics {
|
||||
id: clockTimeTextMetrics
|
||||
text: clockTime.text
|
||||
font: clockTime.font
|
||||
}
|
||||
Text {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
id: clockTime
|
||||
font.bold: false
|
||||
font.pixelSize: 36
|
||||
font.family: "Rawline"
|
||||
color: "#afafaf"
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: loginItem
|
||||
width: loginTextMetrics.width
|
||||
height: loginTextMetrics.height
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 10
|
||||
right: clockAmPmItem.left
|
||||
rightMargin: 5
|
||||
}
|
||||
Text {
|
||||
id: loginText
|
||||
anchors.right: parent.right
|
||||
text: Account.loggedIn ? tabletRoot.usernameShort : qsTr("Log in")
|
||||
horizontalAlignment: Text.AlignRight
|
||||
Layout.alignment: Qt.AlignRight
|
||||
font.pixelSize: 18
|
||||
font.family: "Rawline"
|
||||
color: "#afafaf"
|
||||
}
|
||||
TextMetrics {
|
||||
id: loginTextMetrics
|
||||
text: loginText.text
|
||||
font: loginText.font
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (!Account.loggedIn) {
|
||||
DialogsManager.showLoginDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
rightContainer.timeChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,10 +178,10 @@ Rectangle {
|
|||
|
||||
function setUsername(newUsername) {
|
||||
username = newUsername;
|
||||
usernameShort = newUsername.substring(0, 8);
|
||||
usernameShort = newUsername.substring(0, 14);
|
||||
|
||||
if (newUsername.length > 8) {
|
||||
usernameShort = usernameShort + "..."
|
||||
if (newUsername.length > 14) {
|
||||
usernameShort = usernameShort + "..."
|
||||
}
|
||||
}
|
||||
|
||||
|
|
20
interface/resources/qml/styles-uit/Rawline.qml
Normal file
20
interface/resources/qml/styles-uit/Rawline.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Rawline.qml
|
||||
//
|
||||
// Created by Wayne Chen on 25 Feb 2019
|
||||
// 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.7
|
||||
|
||||
Text {
|
||||
id: root
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: "Rawline"
|
||||
}
|
20
interface/resources/qml/stylesUit/Rawline.qml
Normal file
20
interface/resources/qml/stylesUit/Rawline.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Rawline.qml
|
||||
//
|
||||
// Created by Wayne Chen on 25 Feb 2019
|
||||
// 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.7
|
||||
|
||||
Text {
|
||||
id: root
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: "Rawline"
|
||||
}
|
|
@ -16,8 +16,8 @@
|
|||
#include <QObject>
|
||||
|
||||
/**jsdoc
|
||||
* The <code>HifiAbout</code> API provides information about the version of Interface that is currently running. It also
|
||||
* provides the ability to open a Web page in an Interface browser window.
|
||||
* The <code>HifiAbout</code> API provides information about the version of Interface that is currently running. It also
|
||||
* has the functionality to open a web page in an Interface browser window.
|
||||
*
|
||||
* @namespace HifiAbout
|
||||
*
|
||||
|
@ -30,9 +30,9 @@
|
|||
* @property {string} qtVersion - The Qt version used in Interface that is currently running. <em>Read-only.</em>
|
||||
*
|
||||
* @example <caption>Report build information for the version of Interface currently running.</caption>
|
||||
* print("HiFi build date: " + HifiAbout.buildDate); // 11 Feb 2019
|
||||
* print("HiFi version: " + HifiAbout.buildVersion); // 0.78.0
|
||||
* print("Qt version: " + HifiAbout.qtVersion); // 5.10.1
|
||||
* print("HiFi build date: " + HifiAbout.buildDate); // Returns the build date of the version of Interface currently running on your machine.
|
||||
* print("HiFi version: " + HifiAbout.buildVersion); // Returns the build version of Interface currently running on your machine.
|
||||
* print("Qt version: " + HifiAbout.qtVersion); // Returns the Qt version details of the version of Interface currently running on your machine.
|
||||
*/
|
||||
|
||||
class AboutUtil : public QObject {
|
||||
|
@ -52,9 +52,9 @@ public:
|
|||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
* Display a Web page in an Interface browser window.
|
||||
* Display a web page in an Interface browser window.
|
||||
* @function HifiAbout.openUrl
|
||||
* @param {string} url - The URL of the Web page to display.
|
||||
* @param {string} url - The URL of the web page you want to view in Interface.
|
||||
*/
|
||||
void openUrl(const QString &url) const;
|
||||
private:
|
||||
|
|
|
@ -1061,6 +1061,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
connect(PluginManager::getInstance().data(), &PluginManager::inputDeviceRunningChanged,
|
||||
controllerScriptingInterface, &controller::ScriptingInterface::updateRunningInputDevices);
|
||||
|
||||
EntityTree::setEntityClicksCapturedOperator([this] {
|
||||
return _controllerScriptingInterface->areEntityClicksCaptured();
|
||||
});
|
||||
|
||||
_entityClipboard->createRootElement();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -1075,6 +1079,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-SemiBold.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Light.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Regular.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/rawline-500.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Bold.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-SemiBold.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Cairo-SemiBold.ttf");
|
||||
|
@ -4391,7 +4396,6 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
|
||||
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_ENTITY_ID) {
|
||||
getEntities()->mouseMoveEvent(&mappedEvent);
|
||||
getOverlays().mouseMoveEvent(&mappedEvent);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
|
||||
|
@ -4425,14 +4429,8 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
#endif
|
||||
|
||||
QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers());
|
||||
std::pair<float, QUuid> entityResult;
|
||||
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
|
||||
entityResult = getEntities()->mousePressEvent(&mappedEvent);
|
||||
}
|
||||
std::pair<float, QUuid> overlayResult = getOverlays().mousePressEvent(&mappedEvent);
|
||||
|
||||
QUuid focusedEntity = entityResult.first < overlayResult.first ? entityResult.second : overlayResult.second;
|
||||
setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(focusedEntity) ? focusedEntity : UNKNOWN_ENTITY_ID);
|
||||
QUuid result = getEntities()->mousePressEvent(&mappedEvent);
|
||||
setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(result) ? result : UNKNOWN_ENTITY_ID);
|
||||
|
||||
_controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
|
||||
|
||||
|
@ -4471,11 +4469,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) {
|
|||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
event->buttons(), event->modifiers());
|
||||
|
||||
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
|
||||
getEntities()->mouseDoublePressEvent(&mappedEvent);
|
||||
}
|
||||
getOverlays().mouseDoublePressEvent(&mappedEvent);
|
||||
getEntities()->mouseDoublePressEvent(&mappedEvent);
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||
|
@ -4500,7 +4494,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
|||
event->buttons(), event->modifiers());
|
||||
|
||||
getEntities()->mouseReleaseEvent(&mappedEvent);
|
||||
getOverlays().mouseReleaseEvent(&mappedEvent);
|
||||
|
||||
_controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
|
||||
|
||||
|
@ -6950,7 +6943,7 @@ void Application::clearDomainOctreeDetails(bool clearAll) {
|
|||
});
|
||||
|
||||
// reset the model renderer
|
||||
clearAll ? getEntities()->clear() : getEntities()->clearNonLocalEntities();
|
||||
clearAll ? getEntities()->clear() : getEntities()->clearDomainAndNonOwnedEntities();
|
||||
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
|
||||
|
|
|
@ -62,8 +62,8 @@ public:
|
|||
* <tr><th>Value</th><th>Meaning</th><th>Description</th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td><code>0</code></td><td>Not logged in</td><td>The user isn't logged in.</td></tr>
|
||||
* <tr><td><code>1</code></td><td>Not set up</td><td>The user's wallet isn't set up.</td></tr>
|
||||
* <tr><td><code>0</code></td><td>Not logged in</td><td>The user is not logged in.</td></tr>
|
||||
* <tr><td><code>1</code></td><td>Not set up</td><td>The user's wallet has not been set up.</td></tr>
|
||||
* <tr><td><code>2</code></td><td>Pre-existing</td><td>There is a wallet present on the server but not one
|
||||
* locally.</td></tr>
|
||||
* <tr><td><code>3</code></td><td>Conflicting</td><td>There is a wallet present on the server plus one present locally,
|
||||
|
@ -73,8 +73,8 @@ public:
|
|||
* <tr><td><code>5</code></td><td>Ready</td><td>The wallet is ready for use.</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>Wallets used to be stored locally but now they're stored on the server, unless the computer once had a wallet stored
|
||||
* locally in which case the wallet may be present in both places.</p>
|
||||
* <p>Wallets used to be stored locally but now they're only stored on the server. A wallet is present in both places if
|
||||
* your computer previously stored its information locally.</p>
|
||||
* @typedef {number} WalletScriptingInterface.WalletStatus
|
||||
*/
|
||||
enum WalletStatus {
|
||||
|
|
|
@ -172,7 +172,10 @@ void LaserPointer::RenderState::update(const glm::vec3& origin, const glm::vec3&
|
|||
properties.setVisible(true);
|
||||
properties.setIgnorePickIntersection(doesPathIgnorePicks());
|
||||
QVector<float> widths;
|
||||
widths.append(getLineWidth() * parentScale);
|
||||
float width = getLineWidth() * parentScale;
|
||||
widths.append(width);
|
||||
widths.append(width);
|
||||
properties.setStrokeWidths(widths);
|
||||
DependencyManager::get<EntityScriptingInterface>()->editEntity(getPathID(), properties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,8 +115,8 @@ DownloadInfoResult::DownloadInfoResult() :
|
|||
/**jsdoc
|
||||
* Information on the assets currently being downloaded and pending download.
|
||||
* @typedef {object} AccountServices.DownloadInfoResult
|
||||
* @property {number[]} downloading - The percentage complete for each asset currently being downloaded.
|
||||
* @property {number} pending - The number of assets waiting to be download.
|
||||
* @property {number[]} downloading - The download percentage remaining of each asset currently downloading.
|
||||
* @property {number} pending - The number of assets pending download.
|
||||
*/
|
||||
QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) {
|
||||
QScriptValue object = engine->newObject();
|
||||
|
|
|
@ -38,19 +38,19 @@ class AccountServicesScriptingInterface : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
/**jsdoc
|
||||
* The <code>AccountServices</code> API provides functions related to user connectivity, visibility, and asset download
|
||||
* progress.
|
||||
* The <code>AccountServices</code> API provides functions that give information on user connectivity, visibility, and
|
||||
* asset download progress.
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
* @hifi-avatar
|
||||
*
|
||||
* @namespace AccountServices
|
||||
* @property {string} username - The user name if the user is logged in, otherwise <code>"Unknown user"</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {string} username - The user name of the user logged in. If there is no user logged in, it is
|
||||
* <code>"Unknown user"</code>. <em>Read-only.</em>
|
||||
* @property {boolean} loggedIn - <code>true</code> if the user is logged in, otherwise <code>false</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {string} findableBy - The user's visibility to other people:<br />
|
||||
* @property {string} findableBy - The user's visibility to other users:<br />
|
||||
* <code>"none"</code> - user appears offline.<br />
|
||||
* <code>"friends"</code> - user is visible only to friends.<br />
|
||||
* <code>"connections"</code> - user is visible to friends and connections.<br />
|
||||
|
@ -74,23 +74,23 @@ public:
|
|||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
* Get information on the progress of downloading assets in the domain.
|
||||
* Gets information on the download progress of assets in the domain.
|
||||
* @function AccountServices.getDownloadInfo
|
||||
* @returns {AccountServices.DownloadInfoResult} Information on the progress of assets download.
|
||||
* @returns {AccountServices.DownloadInfoResult} Information on the download progress of assets.
|
||||
*/
|
||||
DownloadInfoResult getDownloadInfo();
|
||||
|
||||
/**jsdoc
|
||||
* Cause a {@link AccountServices.downloadInfoChanged|downloadInfoChanged} signal to be triggered with information on the
|
||||
* current progress of the download of assets in the domain.
|
||||
* Triggers a {@link AccountServices.downloadInfoChanged|downloadInfoChanged} signal with information on the current
|
||||
* download progress of the assets in the domain.
|
||||
* @function AccountServices.updateDownloadInfo
|
||||
*/
|
||||
void updateDownloadInfo();
|
||||
|
||||
/**jsdoc
|
||||
* Check whether the user is logged in.
|
||||
* Checks whether the user is logged in.
|
||||
* @function AccountServices.isLoggedIn
|
||||
* @returns {boolean} <code>true</code> if the user is logged in, <code>false</code> otherwise.
|
||||
* @returns {boolean} <code>true</code> if the user is logged in, <code>false</code> if not.
|
||||
* @example <caption>Report whether you are logged in.</caption>
|
||||
* var isLoggedIn = AccountServices.isLoggedIn();
|
||||
* print("You are logged in: " + isLoggedIn); // true or false
|
||||
|
@ -98,9 +98,9 @@ public slots:
|
|||
bool isLoggedIn();
|
||||
|
||||
/**jsdoc
|
||||
* Prompts the user to log in (the login dialog is displayed) if they're not already logged in.
|
||||
* The function returns the login status of the user and prompts the user to log in (with a login dialog) if they're not already logged in.
|
||||
* @function AccountServices.checkAndSignalForAccessToken
|
||||
* @returns {boolean} <code>true</code> if the user is already logged in, <code>false</code> otherwise.
|
||||
* @returns {boolean} <code>true</code> if the user is logged in, <code>false</code> if not.
|
||||
*/
|
||||
bool checkAndSignalForAccessToken();
|
||||
|
||||
|
@ -140,7 +140,7 @@ signals:
|
|||
/**jsdoc
|
||||
* Triggered when the username logged in with changes, i.e., when the user logs in or out.
|
||||
* @function AccountServices.myUsernameChanged
|
||||
* @param {string} username - The username logged in with if the user is logged in, otherwise <code>""</code>.
|
||||
* @param {string} username - The user name of the user logged in. If there is no user logged in, it is <code>""</code>.
|
||||
* @returns {Signal}
|
||||
* @example <caption>Report when your username changes.</caption>
|
||||
* AccountServices.myUsernameChanged.connect(function (username) {
|
||||
|
@ -150,9 +150,9 @@ signals:
|
|||
void myUsernameChanged(const QString& username);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the progress of the download of assets for the domain changes.
|
||||
* Triggered when the download progress of the assets in the domain changes.
|
||||
* @function AccountServices.downloadInfoChanged
|
||||
* @param {AccountServices.DownloadInfoResult} downloadInfo - Information on the progress of assets download.
|
||||
* @param {AccountServices.DownloadInfoResult} downloadInfo - Information on the download progress of assets.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void downloadInfoChanged(DownloadInfoResult info);
|
||||
|
@ -186,7 +186,7 @@ signals:
|
|||
/**jsdoc
|
||||
* Triggered when the login status of the user changes.
|
||||
* @function AccountServices.loggedInChanged
|
||||
* @param {boolean} loggedIn - <code>true</code> if the user is logged in, otherwise <code>false</code>.
|
||||
* @param {boolean} loggedIn - <code>true</code> if the user is logged in, <code>false</code> if not.
|
||||
* @returns {Signal}
|
||||
* @example <caption>Report when your login status changes.</caption>
|
||||
* AccountServices.loggedInChanged.connect(function(loggedIn) {
|
||||
|
|
|
@ -41,8 +41,8 @@ public:
|
|||
*
|
||||
* @property {WalletScriptingInterface.WalletStatus} walletStatus - The status of the user's wallet. <em>Read-only.</em>
|
||||
* @property {boolean} limitedCommerce - <code>true</code> if Interface is running in limited commerce mode. In limited commerce
|
||||
* mode, certain Interface functionality is disabled, e.g., users can't buy non-free items from the Marketplace. The Oculus
|
||||
* Store version of Interface runs in limited commerce mode. <em>Read-only.</em>
|
||||
* mode, certain Interface functionalities are disabled, e.g., users can't buy items that are not free from the Marketplace.
|
||||
* The Oculus Store version of Interface runs in limited commerce mode. <em>Read-only.</em>
|
||||
*/
|
||||
class WalletScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -55,16 +55,16 @@ public:
|
|||
WalletScriptingInterface();
|
||||
|
||||
/**jsdoc
|
||||
* Check and update the user's wallet status.
|
||||
* Checks and updates the user's wallet status.
|
||||
* @function WalletScriptingInterface.refreshWalletStatus
|
||||
*/
|
||||
Q_INVOKABLE void refreshWalletStatus();
|
||||
|
||||
/**jsdoc
|
||||
* Get the current status of the user's wallet.
|
||||
* Gets the current status of the user's wallet.
|
||||
* @function WalletScriptingInterface.getWalletStatus
|
||||
* @returns {WalletScriptingInterface.WalletStatus}
|
||||
* @example <caption>Two ways to report your wallet status.</caption>
|
||||
* @example <caption>Use two methods to report your wallet's status.</caption>
|
||||
* print("Wallet status: " + WalletScriptingInterface.walletStatus); // Same value as next line.
|
||||
* print("Wallet status: " + WalletScriptingInterface.getWalletStatus());
|
||||
*/
|
||||
|
@ -74,11 +74,11 @@ public:
|
|||
* Check that a certified avatar entity is owned by the avatar whose entity it is. The result of the check is provided via
|
||||
* the {@link WalletScriptingInterface.ownershipVerificationSuccess|ownershipVerificationSuccess} and
|
||||
* {@link WalletScriptingInterface.ownershipVerificationFailed|ownershipVerificationFailed} signals.<br />
|
||||
* <strong>Warning:</strong> Neither of these signals fire if the entity is not an avatar entity or it's not a certified
|
||||
* entity.
|
||||
* <strong>Warning:</strong> Neither of these signals are triggered if the entity is not an avatar entity or is not
|
||||
* certified.
|
||||
* @function WalletScriptingInterface.proveAvatarEntityOwnershipVerification
|
||||
* @param {Uuid} entityID - The ID of the avatar entity to check.
|
||||
* @example <caption>Check ownership of all nearby certified avatar entities.</caption>
|
||||
* @param {Uuid} entityID - The avatar entity's ID.
|
||||
* @example <caption>Check the ownership of all nearby certified avatar entities.</caption>
|
||||
* // Set up response handling.
|
||||
* function ownershipSuccess(entityID) {
|
||||
* print("Ownership test succeeded for: " + entityID);
|
||||
|
@ -118,7 +118,7 @@ public:
|
|||
signals:
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the status of the user's wallet changes.
|
||||
* Triggered when the user's wallet status changes.
|
||||
* @function WalletScriptingInterface.walletStatusChanged
|
||||
* @returns {Signal}
|
||||
* @example <caption>Report when your wallet status changes, e.g., when you log in and out.</caption>
|
||||
|
@ -136,7 +136,7 @@ signals:
|
|||
void limitedCommerceChanged();
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the user rezzes a certified entity but the user's wallet is not ready and so the certified location of the
|
||||
* Triggered when the user rezzes a certified entity but the user's wallet is not ready. So the certified location of the
|
||||
* entity cannot be updated in the metaverse.
|
||||
* @function WalletScriptingInterface.walletNotSetup
|
||||
* @returns {Signal}
|
||||
|
|
|
@ -43,14 +43,6 @@ std::unordered_map<QString, QString> Overlays::_entityToOverlayTypes;
|
|||
std::unordered_map<QString, QString> Overlays::_overlayToEntityTypes;
|
||||
|
||||
Overlays::Overlays() {
|
||||
auto pointerManager = DependencyManager::get<PointerManager>();
|
||||
connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, this, &Overlays::hoverEnterPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::hoverEndOverlay, this, &Overlays::hoverLeavePointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, this, &Overlays::mousePressPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, this, &Overlays::mouseMovePointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerEndOverlay, this, &Overlays::mouseReleasePointerEvent);
|
||||
|
||||
ADD_TYPE_MAP(Box, cube);
|
||||
ADD_TYPE_MAP(Sphere, sphere);
|
||||
_overlayToEntityTypes["rectangle3d"] = "Shape";
|
||||
|
@ -81,13 +73,23 @@ void Overlays::cleanupAllOverlays() {
|
|||
|
||||
void Overlays::init() {
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
|
||||
auto pointerManager = DependencyManager::get<PointerManager>();
|
||||
connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, entityScriptingInterface , &EntityScriptingInterface::hoverEnterEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverEndOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerEndOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||
auto pointerManager = DependencyManager::get<PointerManager>().data();
|
||||
connect(pointerManager, &PointerManager::hoverBeginOverlay, entityScriptingInterface , &EntityScriptingInterface::hoverEnterEntity);
|
||||
connect(pointerManager, &PointerManager::hoverContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
||||
connect(pointerManager, &PointerManager::hoverEndOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
||||
connect(pointerManager, &PointerManager::triggerBeginOverlay, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
||||
connect(pointerManager, &PointerManager::triggerContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
||||
connect(pointerManager, &PointerManager::triggerEndOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &Overlays::mousePressOnPointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOffEntity, this, &Overlays::mousePressOffPointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mouseDoublePressOnEntity, this, &Overlays::mouseDoublePressOnPointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mouseDoublePressOffEntity, this, &Overlays::mouseDoublePressOffPointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, &Overlays::mouseReleasePointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity, this, &Overlays::mouseMovePointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity , this, &Overlays::hoverEnterPointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity, this, &Overlays::hoverOverPointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &Overlays::hoverLeavePointerEvent);
|
||||
}
|
||||
|
||||
void Overlays::update(float deltatime) {
|
||||
|
@ -413,32 +415,13 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
|
|||
overlayProps["dimensions"] = vec3toVariant(ratio * dimensions);
|
||||
}
|
||||
|
||||
if (add || overlayProps.contains("rotation")) {
|
||||
glm::quat rotation;
|
||||
{
|
||||
auto iter = overlayProps.find("rotation");
|
||||
if (iter != overlayProps.end()) {
|
||||
rotation = quatFromVariant(iter.value());
|
||||
} else if (!add) {
|
||||
EntityPropertyFlags desiredProperties;
|
||||
desiredProperties += PROP_ROTATION;
|
||||
rotation = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id, desiredProperties).getRotation();
|
||||
}
|
||||
}
|
||||
if (add && !overlayProps.contains("rotation") && !overlayProps.contains("localRotation")) {
|
||||
overlayProps["rotation"] = quatToVariant(glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT));
|
||||
} else if (overlayProps.contains("rotation")) {
|
||||
glm::quat rotation = quatFromVariant(overlayProps["rotation"]);
|
||||
overlayProps["rotation"] = quatToVariant(glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation);
|
||||
}
|
||||
if (add || overlayProps.contains("localRotation")) {
|
||||
glm::quat rotation;
|
||||
{
|
||||
auto iter = overlayProps.find("localRotation");
|
||||
if (iter != overlayProps.end()) {
|
||||
rotation = quatFromVariant(iter.value());
|
||||
} else if (!add) {
|
||||
EntityPropertyFlags desiredProperties;
|
||||
desiredProperties += PROP_LOCAL_ROTATION;
|
||||
rotation = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id, desiredProperties).getLocalRotation();
|
||||
}
|
||||
}
|
||||
} else if (overlayProps.contains("localRotation")) {
|
||||
glm::quat rotation = quatFromVariant(overlayProps["localRotation"]);
|
||||
overlayProps["localRotation"] = quatToVariant(glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation);
|
||||
}
|
||||
|
||||
|
@ -1178,7 +1161,7 @@ bool Overlays::isAddedOverlay(const QUuid& id) {
|
|||
}
|
||||
|
||||
void Overlays::sendMousePressOnOverlay(const QUuid& id, const PointerEvent& event) {
|
||||
mousePressPointerEvent(id, event);
|
||||
mousePressOnPointerEvent(id, event);
|
||||
}
|
||||
|
||||
void Overlays::sendMouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event) {
|
||||
|
@ -1225,57 +1208,66 @@ float Overlays::height() {
|
|||
return offscreenUi->getWindow()->size().height();
|
||||
}
|
||||
|
||||
static uint32_t toPointerButtons(const QMouseEvent& event) {
|
||||
uint32_t buttons = 0;
|
||||
buttons |= event.buttons().testFlag(Qt::LeftButton) ? PointerEvent::PrimaryButton : 0;
|
||||
buttons |= event.buttons().testFlag(Qt::RightButton) ? PointerEvent::SecondaryButton : 0;
|
||||
buttons |= event.buttons().testFlag(Qt::MiddleButton) ? PointerEvent::TertiaryButton : 0;
|
||||
return buttons;
|
||||
}
|
||||
|
||||
static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
|
||||
switch (event.button()) {
|
||||
case Qt::LeftButton:
|
||||
return PointerEvent::PrimaryButton;
|
||||
case Qt::RightButton:
|
||||
return PointerEvent::SecondaryButton;
|
||||
case Qt::MiddleButton:
|
||||
return PointerEvent::TertiaryButton;
|
||||
default:
|
||||
return PointerEvent::NoButtons;
|
||||
}
|
||||
}
|
||||
|
||||
RayToOverlayIntersectionResult getPrevPickResult() {
|
||||
RayToOverlayIntersectionResult overlayResult;
|
||||
overlayResult.intersects = false;
|
||||
auto pickResult = DependencyManager::get<PickManager>()->getPrevPickResultTyped<RayPickResult>(DependencyManager::get<EntityTreeRenderer>()->getMouseRayPickID());
|
||||
if (pickResult) {
|
||||
overlayResult.intersects = pickResult->type == IntersectionType::LOCAL_ENTITY;
|
||||
if (overlayResult.intersects) {
|
||||
overlayResult.intersection = pickResult->intersection;
|
||||
overlayResult.distance = pickResult->distance;
|
||||
overlayResult.surfaceNormal = pickResult->surfaceNormal;
|
||||
overlayResult.overlayID = pickResult->objectID;
|
||||
overlayResult.extraInfo = pickResult->extraInfo;
|
||||
void Overlays::mousePressOnPointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit mousePressOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
return overlayResult;
|
||||
}
|
||||
|
||||
PointerEvent Overlays::calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray,
|
||||
const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event,
|
||||
PointerEvent::EventType eventType) {
|
||||
glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(id, rayPickResult.intersection);
|
||||
return PointerEvent(eventType, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal,
|
||||
ray.direction, toPointerButton(*event), toPointerButtons(*event), event->modifiers());
|
||||
void Overlays::mousePressOffPointerEvent() {
|
||||
emit mousePressOffOverlay();
|
||||
}
|
||||
|
||||
void Overlays::mouseDoublePressOnPointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit mouseDoublePressOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Overlays::mouseDoublePressOffPointerEvent() {
|
||||
emit mouseDoublePressOffOverlay();
|
||||
}
|
||||
|
||||
void Overlays::mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit mouseReleaseOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Overlays::mouseMovePointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit mouseMoveOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Overlays::hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
emit hoverEnterOverlay(id, event);
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit hoverEnterOverlay(id, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1283,7 +1275,10 @@ void Overlays::hoverOverPointerEvent(const QUuid& id, const PointerEvent& event)
|
|||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
emit hoverOverOverlay(id, event);
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit hoverOverOverlay(id, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1291,113 +1286,10 @@ void Overlays::hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event
|
|||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
emit hoverLeaveOverlay(id, event);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<float, QUuid> Overlays::mousePressEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mousePressEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||
|
||||
PointerEvent pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
|
||||
mousePressPointerEvent(_currentClickingOnOverlayID, pointerEvent);
|
||||
return { rayPickResult.distance, rayPickResult.overlayID };
|
||||
}
|
||||
emit mousePressOffOverlay();
|
||||
return { FLT_MAX, UNKNOWN_ENTITY_ID };
|
||||
}
|
||||
|
||||
void Overlays::mousePressPointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
emit mousePressOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
|
||||
bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||
|
||||
auto pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
|
||||
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||
return true;
|
||||
}
|
||||
emit mouseDoublePressOffOverlay();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
|
||||
mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||
}
|
||||
|
||||
_currentClickingOnOverlayID = UNKNOWN_ENTITY_ID;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Overlays::mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
emit mouseReleaseOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
|
||||
bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||
|
||||
// If previously hovering over a different overlay then leave hover on that overlay.
|
||||
if (_currentHoverOverOverlayID != UNKNOWN_ENTITY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
hoverLeavePointerEvent(_currentHoverOverOverlayID, pointerEvent);
|
||||
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
|
||||
if (entity && entity->isLocalEntity()) {
|
||||
emit hoverLeaveOverlay(id, event);
|
||||
}
|
||||
|
||||
// If hovering over a new overlay then enter hover on that overlay.
|
||||
if (rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
||||
hoverEnterPointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||
}
|
||||
|
||||
// Hover over current overlay.
|
||||
hoverOverPointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||
|
||||
_currentHoverOverOverlayID = rayPickResult.overlayID;
|
||||
} else {
|
||||
// If previously hovering an overlay then leave hover.
|
||||
if (_currentHoverOverOverlayID != UNKNOWN_ENTITY_ID) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
hoverLeavePointerEvent(_currentHoverOverOverlayID, pointerEvent);
|
||||
|
||||
_currentHoverOverOverlayID = UNKNOWN_ENTITY_ID;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Overlays::mouseMovePointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
auto keyboard = DependencyManager::get<Keyboard>();
|
||||
// Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed
|
||||
if (!keyboard->getKeyIDs().contains(id)) {
|
||||
emit mouseMoveOnOverlay(id, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,11 +112,6 @@ public:
|
|||
const QVector<EntityItemID>& discard,
|
||||
bool visibleOnly = false, bool collidableOnly = false);
|
||||
|
||||
std::pair<float, QUuid> mousePressEvent(QMouseEvent* event);
|
||||
bool mouseDoublePressEvent(QMouseEvent* event);
|
||||
bool mouseReleaseEvent(QMouseEvent* event);
|
||||
bool mouseMoveEvent(QMouseEvent* event);
|
||||
|
||||
void cleanupAllOverlays();
|
||||
|
||||
mutable QScriptEngine _scriptEngine;
|
||||
|
@ -719,9 +714,6 @@ private:
|
|||
PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
|
||||
QMouseEvent* event, PointerEvent::EventType eventType);
|
||||
|
||||
QUuid _currentClickingOnOverlayID;
|
||||
QUuid _currentHoverOverOverlayID;
|
||||
|
||||
static QString entityToOverlayType(const QString& type);
|
||||
static QString overlayToEntityType(const QString& type);
|
||||
static std::unordered_map<QString, QString> _entityToOverlayTypes;
|
||||
|
@ -732,12 +724,17 @@ private:
|
|||
EntityItemProperties convertOverlayToEntityProperties(QVariantMap& overlayProps, std::pair<glm::quat, bool>& rotationToSave, const QString& type, bool add, const QUuid& id = QUuid());
|
||||
|
||||
private slots:
|
||||
void mousePressPointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void mousePressOnPointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void mousePressOffPointerEvent();
|
||||
void mouseDoublePressOnPointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void mouseDoublePressOffPointerEvent();
|
||||
void mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void hoverOverPointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
void hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#define ADD_TYPE_MAP(entity, overlay) \
|
||||
|
|
|
@ -123,6 +123,42 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
const int animFrameCount = animModel.animationFrames.size();
|
||||
_anim.resize(animFrameCount);
|
||||
|
||||
// find the size scale factor for translation in the animation.
|
||||
const int avatarHipsParentIndex = avatarSkeleton->getParentIndex(avatarSkeleton->nameToJointIndex("Hips"));
|
||||
const int animHipsParentIndex = animSkeleton.getParentIndex(animSkeleton.nameToJointIndex("Hips"));
|
||||
const AnimPose& avatarHipsAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarSkeleton->nameToJointIndex("Hips"));
|
||||
const AnimPose& animHipsAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animSkeleton.nameToJointIndex("Hips"));
|
||||
|
||||
// the get the units and the heights for the animation and the avatar
|
||||
const float avatarUnitScale = extractScale(avatarSkeleton->getGeometryOffset()).y;
|
||||
const float animationUnitScale = extractScale(animModel.offset).y;
|
||||
const float avatarHeightInMeters = avatarUnitScale * avatarHipsAbsoluteDefaultPose.trans().y;
|
||||
const float animHeightInMeters = animationUnitScale * animHipsAbsoluteDefaultPose.trans().y;
|
||||
|
||||
// get the parent scales for the avatar and the animation
|
||||
float avatarHipsParentScale = 1.0f;
|
||||
if (avatarHipsParentIndex >= 0) {
|
||||
const AnimPose& avatarHipsParentAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarHipsParentIndex);
|
||||
avatarHipsParentScale = avatarHipsParentAbsoluteDefaultPose.scale().y;
|
||||
}
|
||||
float animHipsParentScale = 1.0f;
|
||||
if (animHipsParentIndex >= 0) {
|
||||
const AnimPose& animationHipsParentAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animHipsParentIndex);
|
||||
animHipsParentScale = animationHipsParentAbsoluteDefaultPose.scale().y;
|
||||
}
|
||||
|
||||
const float EPSILON = 0.0001f;
|
||||
float boneLengthScale = 1.0f;
|
||||
// compute the ratios for the units, the heights in meters, and the parent scales
|
||||
if ((fabsf(animHeightInMeters) > EPSILON) && (animationUnitScale > EPSILON) && (animHipsParentScale > EPSILON)) {
|
||||
const float avatarToAnimationHeightRatio = avatarHeightInMeters / animHeightInMeters;
|
||||
const float unitsRatio = 1.0f / (avatarUnitScale / animationUnitScale);
|
||||
const float parentScaleRatio = 1.0f / (avatarHipsParentScale / animHipsParentScale);
|
||||
|
||||
boneLengthScale = avatarToAnimationHeightRatio * unitsRatio * parentScaleRatio;
|
||||
}
|
||||
|
||||
|
||||
for (int frame = 0; frame < animFrameCount; frame++) {
|
||||
const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
|
||||
|
||||
|
@ -162,7 +198,6 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations);
|
||||
|
||||
_anim[frame].reserve(avatarJointCount);
|
||||
|
||||
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
||||
|
||||
|
@ -177,11 +212,6 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
|
||||
// retarget translation from animation to avatar
|
||||
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
|
||||
float boneLengthScale = 1.0f;
|
||||
const float EPSILON = 0.0001f;
|
||||
if (fabsf(glm::length(animZeroTrans)) > EPSILON) {
|
||||
boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans);
|
||||
}
|
||||
relativeTranslation = avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans);
|
||||
} else {
|
||||
// This joint is NOT in the animation at all.
|
||||
|
|
|
@ -298,10 +298,8 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
|
|||
}
|
||||
|
||||
// harvest accumulated rotations and apply the average
|
||||
for (int i = 0; i < (int)_relativePoses.size(); ++i) {
|
||||
if (i == _hipsIndex) {
|
||||
continue; // don't apply accumulators to hips
|
||||
}
|
||||
// don't apply accumulators to hips, or parents of hips
|
||||
for (int i = (_hipsIndex+1); i < (int)_relativePoses.size(); ++i) {
|
||||
if (_rotationAccumulators[i].size() > 0) {
|
||||
_relativePoses[i].rot() = _rotationAccumulators[i].getAverage();
|
||||
_rotationAccumulators[i].clear();
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include "AnimationLogging.h"
|
||||
|
||||
AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
|
||||
|
||||
_geometryOffset = hfmModel.offset;
|
||||
|
||||
// convert to std::vector of joints
|
||||
std::vector<HFMJoint> joints;
|
||||
joints.reserve(hfmModel.joints.size());
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
const AnimPoseVec& getRelativeDefaultPoses() const { return _relativeDefaultPoses; }
|
||||
const AnimPose& getAbsoluteDefaultPose(int jointIndex) const;
|
||||
const AnimPoseVec& getAbsoluteDefaultPoses() const { return _absoluteDefaultPoses; }
|
||||
const glm::mat4& getGeometryOffset() const { return _geometryOffset; }
|
||||
|
||||
// get pre transform which should include FBX pre potations
|
||||
const AnimPose& getPreRotationPose(int jointIndex) const;
|
||||
|
@ -84,6 +85,7 @@ protected:
|
|||
std::vector<int> _mirrorMap;
|
||||
QHash<QString, int> _jointIndicesByName;
|
||||
std::vector<std::vector<HFMCluster>> _clusterBindMatrixOriginalValues;
|
||||
glm::mat4 _geometryOffset;
|
||||
|
||||
// no copies
|
||||
AnimSkeleton(const AnimSkeleton&) = delete;
|
||||
|
|
|
@ -73,14 +73,14 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
|
||||
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
|
||||
auto pointerManager = DependencyManager::get<PointerManager>();
|
||||
connect(pointerManager.data(), &PointerManager::hoverBeginEntity, entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverContinueEntity, entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverEndEntity, entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerBeginEntity, entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerContinueEntity, entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerEndEntity, entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverBeginEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverContinueEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
||||
connect(pointerManager.data(), &PointerManager::hoverEndEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerBeginEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerContinueEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
||||
connect(pointerManager.data(), &PointerManager::triggerEndEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||
|
||||
// Forward mouse events to web entities
|
||||
auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
|
@ -93,10 +93,10 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
QMetaObject::invokeMethod(thisEntity.get(), "handlePointerEvent", Q_ARG(const PointerEvent&, event));
|
||||
}
|
||||
};
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||
|
@ -106,8 +106,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
QMetaObject::invokeMethod(thisEntity.get(), "hoverEnterEntity", Q_ARG(const PointerEvent&, event));
|
||||
}
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||
|
@ -196,8 +196,8 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
|||
});
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::stopNonLocalEntityScripts() {
|
||||
leaveNonLocalEntities();
|
||||
void EntityTreeRenderer::stopDomainAndNonOwnedEntities() {
|
||||
leaveDomainAndNonOwnedEntities();
|
||||
// unload and stop the engine
|
||||
if (_entitiesScriptEngine) {
|
||||
QList<EntityItemID> entitiesWithEntityScripts = _entitiesScriptEngine->getListOfEntityScriptIDs();
|
||||
|
@ -206,7 +206,7 @@ void EntityTreeRenderer::stopNonLocalEntityScripts() {
|
|||
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
|
||||
|
||||
if (entityItem) {
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
}
|
||||
}
|
||||
|
@ -214,8 +214,8 @@ void EntityTreeRenderer::stopNonLocalEntityScripts() {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clearNonLocalEntities() {
|
||||
stopNonLocalEntityScripts();
|
||||
void EntityTreeRenderer::clearDomainAndNonOwnedEntities() {
|
||||
stopDomainAndNonOwnedEntities();
|
||||
|
||||
std::unordered_map<EntityItemID, EntityRendererPointer> savedEntities;
|
||||
// remove all entities from the scene
|
||||
|
@ -225,7 +225,7 @@ void EntityTreeRenderer::clearNonLocalEntities() {
|
|||
for (const auto& entry : _entitiesInScene) {
|
||||
const auto& renderer = entry.second;
|
||||
const EntityItemPointer& entityItem = renderer->getEntity();
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) {
|
||||
renderer->removeFromScene(scene, transaction);
|
||||
} else {
|
||||
savedEntities[entry.first] = entry.second;
|
||||
|
@ -239,7 +239,7 @@ void EntityTreeRenderer::clearNonLocalEntities() {
|
|||
|
||||
_layeredZones.clearNonLocalLayeredZones();
|
||||
|
||||
OctreeProcessor::clearNonLocalEntities();
|
||||
OctreeProcessor::clearDomainAndNonOwnedEntities();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clear() {
|
||||
|
@ -655,22 +655,22 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
return didUpdate;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveNonLocalEntities() {
|
||||
void EntityTreeRenderer::leaveDomainAndNonOwnedEntities() {
|
||||
if (_tree && !_shuttingDown) {
|
||||
QVector<EntityItemID> currentLocalEntitiesInside;
|
||||
QVector<EntityItemID> currentEntitiesInsideToSave;
|
||||
foreach (const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) {
|
||||
emit leaveEntity(entityID);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
}
|
||||
} else {
|
||||
currentLocalEntitiesInside.push_back(entityID);
|
||||
currentEntitiesInsideToSave.push_back(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
_currentEntitiesInside = currentLocalEntitiesInside;
|
||||
_currentEntitiesInside = currentEntitiesInsideToSave;
|
||||
forceRecheckEntities();
|
||||
}
|
||||
}
|
||||
|
@ -792,11 +792,11 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<float, QUuid> EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
||||
QUuid EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
||||
// If we don't have a tree, or we're in the process of shutting down, then don't
|
||||
// process these events.
|
||||
if (!_tree || _shuttingDown) {
|
||||
return { FLT_MAX, UNKNOWN_ENTITY_ID };
|
||||
return UNKNOWN_ENTITY_ID;
|
||||
}
|
||||
|
||||
PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent");
|
||||
|
@ -805,11 +805,13 @@ std::pair<float, QUuid> EntityTreeRenderer::mousePressEvent(QMouseEvent* event)
|
|||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
EntityItemPointer entity;
|
||||
if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) {
|
||||
auto properties = entity->getProperties();
|
||||
QString urlString = properties.getHref();
|
||||
QUrl url = QUrl(urlString, QUrl::StrictMode);
|
||||
if (url.isValid() && !url.isEmpty()){
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
|
||||
if (!EntityTree::areEntityClicksCaptured()) {
|
||||
auto properties = entity->getProperties();
|
||||
QString urlString = properties.getHref();
|
||||
QUrl url = QUrl(urlString, QUrl::StrictMode);
|
||||
if (url.isValid() && !url.isEmpty()) {
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
|
||||
|
@ -827,10 +829,10 @@ std::pair<float, QUuid> EntityTreeRenderer::mousePressEvent(QMouseEvent* event)
|
|||
_lastPointerEvent = pointerEvent;
|
||||
_lastPointerEventValid = true;
|
||||
|
||||
return { rayPickResult.distance, rayPickResult.entityID };
|
||||
return rayPickResult.entityID;
|
||||
}
|
||||
emit entityScriptingInterface->mousePressOffEntity();
|
||||
return { FLT_MAX, UNKNOWN_ENTITY_ID };
|
||||
return UNKNOWN_ENTITY_ID;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
|
||||
|
|
|
@ -87,14 +87,14 @@ public:
|
|||
virtual void init() override;
|
||||
|
||||
/// clears the tree
|
||||
virtual void clearNonLocalEntities() override;
|
||||
virtual void clearDomainAndNonOwnedEntities() override;
|
||||
virtual void clear() override;
|
||||
|
||||
/// reloads the entity scripts, calling unload and preload
|
||||
void reloadEntityScripts();
|
||||
|
||||
// event handles which may generate entity related events
|
||||
std::pair<float, QUuid> mousePressEvent(QMouseEvent* event);
|
||||
QUuid mousePressEvent(QMouseEvent* event);
|
||||
void mouseReleaseEvent(QMouseEvent* event);
|
||||
void mouseDoublePressEvent(QMouseEvent* event);
|
||||
void mouseMoveEvent(QMouseEvent* event);
|
||||
|
@ -170,7 +170,7 @@ private:
|
|||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyLayeredZones();
|
||||
void stopNonLocalEntityScripts();
|
||||
void stopDomainAndNonOwnedEntities();
|
||||
|
||||
void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false);
|
||||
|
||||
|
@ -179,7 +179,7 @@ private:
|
|||
|
||||
QScriptValueList createEntityArgs(const EntityItemID& entityID);
|
||||
bool checkEnterLeaveEntities();
|
||||
void leaveNonLocalEntities();
|
||||
void leaveDomainAndNonOwnedEntities();
|
||||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
|
|
|
@ -78,13 +78,14 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) {
|
|||
return std::static_pointer_cast<OctreeElement>(newElement);
|
||||
}
|
||||
|
||||
void EntityTree::eraseNonLocalEntities() {
|
||||
void EntityTree::eraseDomainAndNonOwnedEntities() {
|
||||
emit clearingEntities();
|
||||
|
||||
if (_simulation) {
|
||||
// local entities are not in the simulation, so we clear ALL
|
||||
_simulation->clearEntities();
|
||||
}
|
||||
|
||||
this->withWriteLock([&] {
|
||||
QHash<EntityItemID, EntityItemPointer> savedEntities;
|
||||
// NOTE: lock the Tree first, then lock the _entityMap.
|
||||
|
@ -93,10 +94,10 @@ void EntityTree::eraseNonLocalEntities() {
|
|||
foreach(EntityItemPointer entity, _entityMap) {
|
||||
EntityTreeElementPointer element = entity->getElement();
|
||||
if (element) {
|
||||
element->cleanupNonLocalEntities();
|
||||
element->cleanupDomainAndNonOwnedEntities();
|
||||
}
|
||||
|
||||
if (entity->isLocalEntity()) {
|
||||
if (entity->isLocalEntity() || (entity->isAvatarEntity() && entity->getOwningAvatarID() == getMyAvatarSessionUUID())) {
|
||||
savedEntities[entity->getEntityItemID()] = entity;
|
||||
} else {
|
||||
int32_t spaceIndex = entity->getSpaceIndex();
|
||||
|
@ -114,15 +115,16 @@ void EntityTree::eraseNonLocalEntities() {
|
|||
|
||||
{
|
||||
QWriteLocker locker(&_needsParentFixupLock);
|
||||
QVector<EntityItemWeakPointer> localEntitiesNeedsParentFixup;
|
||||
QVector<EntityItemWeakPointer> needParentFixup;
|
||||
|
||||
foreach (EntityItemWeakPointer entityItem, _needsParentFixup) {
|
||||
if (!entityItem.expired() && entityItem.lock()->isLocalEntity()) {
|
||||
localEntitiesNeedsParentFixup.push_back(entityItem);
|
||||
auto entity = entityItem.lock();
|
||||
if (entity && (entity->isLocalEntity() || (entity->isAvatarEntity() && entity->getOwningAvatarID() == getMyAvatarSessionUUID()))) {
|
||||
needParentFixup.push_back(entityItem);
|
||||
}
|
||||
}
|
||||
|
||||
_needsParentFixup = localEntitiesNeedsParentFixup;
|
||||
_needsParentFixup = needParentFixup;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2972,6 +2974,7 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const {
|
|||
|
||||
std::function<QObject*(const QUuid&)> EntityTree::_getEntityObjectOperator = nullptr;
|
||||
std::function<QSizeF(const QUuid&, const QString&)> EntityTree::_textSizeOperator = nullptr;
|
||||
std::function<bool()> EntityTree::_areEntityClicksCapturedOperator = nullptr;
|
||||
|
||||
QObject* EntityTree::getEntityObject(const QUuid& id) {
|
||||
if (_getEntityObjectOperator) {
|
||||
|
@ -2987,6 +2990,13 @@ QSizeF EntityTree::textSize(const QUuid& id, const QString& text) {
|
|||
return QSizeF(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
bool EntityTree::areEntityClicksCaptured() {
|
||||
if (_areEntityClicksCapturedOperator) {
|
||||
return _areEntityClicksCapturedOperator();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
|
||||
MovingEntitiesOperator& moveOperator, bool force, bool tellServer) {
|
||||
// if the queryBox has changed, tell the entity-server
|
||||
|
|
|
@ -75,7 +75,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual void eraseNonLocalEntities() override;
|
||||
virtual void eraseDomainAndNonOwnedEntities() override;
|
||||
virtual void eraseAllOctreeElements(bool createNewRoot = true) override;
|
||||
|
||||
virtual void readBitstreamToTree(const unsigned char* bitstream,
|
||||
|
@ -255,6 +255,7 @@ public:
|
|||
QByteArray computeNonce(const QString& certID, const QString ownerKey);
|
||||
bool verifyNonce(const QString& certID, const QString& nonce, EntityItemID& id);
|
||||
|
||||
QUuid getMyAvatarSessionUUID() { return _myAvatar ? _myAvatar->getSessionUUID() : QUuid(); }
|
||||
void setMyAvatar(std::shared_ptr<AvatarData> myAvatar) { _myAvatar = myAvatar; }
|
||||
|
||||
void swapStaleProxies(std::vector<int>& proxies) { proxies.swap(_staleProxies); }
|
||||
|
@ -268,6 +269,9 @@ public:
|
|||
static void setTextSizeOperator(std::function<QSizeF(const QUuid&, const QString&)> textSizeOperator) { _textSizeOperator = textSizeOperator; }
|
||||
static QSizeF textSize(const QUuid& id, const QString& text);
|
||||
|
||||
static void setEntityClicksCapturedOperator(std::function<bool()> areEntityClicksCapturedOperator) { _areEntityClicksCapturedOperator = areEntityClicksCapturedOperator; }
|
||||
static bool areEntityClicksCaptured();
|
||||
|
||||
std::map<QString, QString> getNamedPaths() const { return _namedPaths; }
|
||||
|
||||
void updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
|
||||
|
@ -378,6 +382,7 @@ private:
|
|||
|
||||
static std::function<QObject*(const QUuid&)> _getEntityObjectOperator;
|
||||
static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
|
||||
static std::function<bool()> _areEntityClicksCapturedOperator;
|
||||
|
||||
std::vector<int32_t> _staleProxies;
|
||||
|
||||
|
|
|
@ -697,11 +697,11 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI
|
|||
return foundEntity;
|
||||
}
|
||||
|
||||
void EntityTreeElement::cleanupNonLocalEntities() {
|
||||
void EntityTreeElement::cleanupDomainAndNonOwnedEntities() {
|
||||
withWriteLock([&] {
|
||||
EntityItems savedEntities;
|
||||
foreach(EntityItemPointer entity, _entityItems) {
|
||||
if (!entity->isLocalEntity()) {
|
||||
if (!(entity->isLocalEntity() || (entity->isAvatarEntity() && entity->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) {
|
||||
entity->preDelete();
|
||||
entity->_element = NULL;
|
||||
} else {
|
||||
|
|
|
@ -190,7 +190,7 @@ public:
|
|||
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
|
||||
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
void cleanupNonLocalEntities();
|
||||
void cleanupDomainAndNonOwnedEntities();
|
||||
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
|
||||
bool removeEntityItem(EntityItemPointer entity, bool deletion = false);
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ protected:
|
|||
int _lastKnownCurrentFrame{-1};
|
||||
|
||||
glm::u8vec3 _color;
|
||||
glm::vec3 _modelScale;
|
||||
glm::vec3 _modelScale { 1.0f };
|
||||
QString _modelURL;
|
||||
bool _relayParentJoints;
|
||||
bool _groupCulled { false };
|
||||
|
|
|
@ -167,7 +167,6 @@ glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParen
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return globalTransform;
|
||||
}
|
||||
|
||||
|
@ -436,6 +435,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
hfmModel.originalURL = url;
|
||||
|
||||
float unitScaleFactor = 1.0f;
|
||||
glm::quat upAxisZRotation;
|
||||
bool applyUpAxisZRotation = false;
|
||||
glm::vec3 ambientColor;
|
||||
QString hifiGlobalNodeID;
|
||||
unsigned int meshIndex = 0;
|
||||
|
@ -473,11 +474,22 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
if (subobject.name == propertyName) {
|
||||
static const QVariant UNIT_SCALE_FACTOR = QByteArray("UnitScaleFactor");
|
||||
static const QVariant AMBIENT_COLOR = QByteArray("AmbientColor");
|
||||
static const QVariant UP_AXIS = QByteArray("UpAxis");
|
||||
const auto& subpropName = subobject.properties.at(0);
|
||||
if (subpropName == UNIT_SCALE_FACTOR) {
|
||||
unitScaleFactor = subobject.properties.at(index).toFloat();
|
||||
} else if (subpropName == AMBIENT_COLOR) {
|
||||
ambientColor = getVec3(subobject.properties, index);
|
||||
} else if (subpropName == UP_AXIS) {
|
||||
constexpr int UP_AXIS_Y = 1;
|
||||
constexpr int UP_AXIS_Z = 2;
|
||||
int upAxis = subobject.properties.at(index).toInt();
|
||||
if (upAxis == UP_AXIS_Y) {
|
||||
// No update necessary, y up is the default
|
||||
} else if (upAxis == UP_AXIS_Z) {
|
||||
upAxisZRotation = glm::angleAxis(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
applyUpAxisZRotation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1269,9 +1281,11 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
joint.geometricScaling = fbxModel.geometricScaling;
|
||||
joint.isSkeletonJoint = fbxModel.isLimbNode;
|
||||
hfmModel.hasSkeletonJoints = (hfmModel.hasSkeletonJoints || joint.isSkeletonJoint);
|
||||
|
||||
if (applyUpAxisZRotation && joint.parentIndex == -1) {
|
||||
joint.rotation *= upAxisZRotation;
|
||||
joint.translation = upAxisZRotation * joint.translation;
|
||||
}
|
||||
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
joint.transform = hfmModel.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
|
@ -1664,6 +1678,14 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
}
|
||||
}
|
||||
|
||||
if (applyUpAxisZRotation) {
|
||||
hfmModelPtr->meshExtents.transform(glm::mat4_cast(upAxisZRotation));
|
||||
hfmModelPtr->bindExtents.transform(glm::mat4_cast(upAxisZRotation));
|
||||
for (auto &mesh : hfmModelPtr->meshes) {
|
||||
mesh.modelTransform *= glm::mat4_cast(upAxisZRotation);
|
||||
mesh.meshExtents.transform(glm::mat4_cast(upAxisZRotation));
|
||||
}
|
||||
}
|
||||
return hfmModelPtr;
|
||||
}
|
||||
|
||||
|
|
|
@ -353,16 +353,19 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
|||
// We've seen this extra info before
|
||||
resource = resourcesWithExtraHashIter.value().lock();
|
||||
} else if (resourcesWithExtraHash.size() > 0.0f) {
|
||||
// We haven't seen this extra info before, but we've already downloaded the resource. We need a new copy of this object (with any old hash).
|
||||
resource = createResourceCopy(resourcesWithExtraHash.begin().value().lock());
|
||||
resource->setExtra(extra);
|
||||
resource->setExtraHash(extraHash);
|
||||
resource->setSelf(resource);
|
||||
resource->setCache(this);
|
||||
resource->moveToThread(qApp->thread());
|
||||
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
||||
resourcesWithExtraHash.insert(extraHash, resource);
|
||||
resource->ensureLoading();
|
||||
auto oldResource = resourcesWithExtraHash.begin().value().lock();
|
||||
if (oldResource) {
|
||||
// We haven't seen this extra info before, but we've already downloaded the resource. We need a new copy of this object (with any old hash).
|
||||
resource = createResourceCopy(oldResource);
|
||||
resource->setExtra(extra);
|
||||
resource->setExtraHash(extraHash);
|
||||
resource->setSelf(resource);
|
||||
resource->setCache(this);
|
||||
resource->moveToThread(qApp->thread());
|
||||
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
||||
resourcesWithExtraHash.insert(extraHash, resource);
|
||||
resource->ensureLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource) {
|
||||
|
|
|
@ -31,7 +31,6 @@ using namespace udt;
|
|||
using namespace std::chrono;
|
||||
|
||||
Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr<CongestionControl> congestionControl) :
|
||||
QObject(parentSocket),
|
||||
_parentSocket(parentSocket),
|
||||
_destination(destination),
|
||||
_congestionControl(move(congestionControl))
|
||||
|
|
|
@ -251,7 +251,10 @@ Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr, bool fi
|
|||
auto congestionControl = _ccFactory->create();
|
||||
congestionControl->setMaxBandwidth(_maxBandwidth);
|
||||
auto connection = std::unique_ptr<Connection>(new Connection(this, sockAddr, std::move(congestionControl)));
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
qCDebug(networking) << "Moving new Connection to NodeList thread";
|
||||
connection->moveToThread(thread());
|
||||
}
|
||||
// allow higher-level classes to find out when connections have completed a handshake
|
||||
QObject::connect(connection.get(), &Connection::receiverHandshakeRequestComplete,
|
||||
this, &Socket::clientHandshakeRequestComplete);
|
||||
|
|
|
@ -149,7 +149,7 @@ public:
|
|||
|
||||
OctreeElementPointer getRoot() { return _rootElement; }
|
||||
|
||||
virtual void eraseNonLocalEntities() { _isDirty = true; };
|
||||
virtual void eraseDomainAndNonOwnedEntities() { _isDirty = true; };
|
||||
virtual void eraseAllOctreeElements(bool createNewRoot = true);
|
||||
|
||||
virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
|
|
|
@ -198,10 +198,10 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
}
|
||||
|
||||
|
||||
void OctreeProcessor::clearNonLocalEntities() {
|
||||
void OctreeProcessor::clearDomainAndNonOwnedEntities() {
|
||||
if (_tree) {
|
||||
_tree->withWriteLock([&] {
|
||||
_tree->eraseNonLocalEntities();
|
||||
_tree->eraseDomainAndNonOwnedEntities();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
virtual void init();
|
||||
|
||||
/// clears the tree
|
||||
virtual void clearNonLocalEntities();
|
||||
virtual void clearDomainAndNonOwnedEntities();
|
||||
virtual void clear();
|
||||
|
||||
float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); }
|
||||
|
|
|
@ -1346,14 +1346,19 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
}
|
||||
|
||||
void Model::computeMeshPartLocalBounds() {
|
||||
for (auto& part : _modelMeshRenderItems) {
|
||||
const Model::MeshState& state = _meshStates.at(part->_meshIndex);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
part->computeAdjustedLocalBound(state.clusterDualQuaternions);
|
||||
} else {
|
||||
part->computeAdjustedLocalBound(state.clusterMatrices);
|
||||
}
|
||||
render::Transaction transaction;
|
||||
auto meshStates = _meshStates;
|
||||
for (auto renderItem : _modelMeshRenderItemIDs) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(renderItem, [this, meshStates](ModelMeshPartPayload& data) {
|
||||
const Model::MeshState& state = meshStates.at(data._meshIndex);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
data.computeAdjustedLocalBound(state.clusterDualQuaternions);
|
||||
} else {
|
||||
data.computeAdjustedLocalBound(state.clusterMatrices);
|
||||
}
|
||||
});
|
||||
}
|
||||
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
|
@ -976,7 +976,9 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
|||
using PointerHandler = std::function<void(const EntityItemID&, const PointerEvent&)>;
|
||||
auto makePointerHandler = [this](QString eventName) -> PointerHandler {
|
||||
return [this, eventName](const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) });
|
||||
if (!EntityTree::areEntityClicksCaptured()) {
|
||||
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -30,6 +30,20 @@
|
|||
100,
|
||||
makeLaserParams((this.hand + HUD_LASER_OFFSET), false));
|
||||
|
||||
this.getFarGrab = function () {
|
||||
return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity"));
|
||||
}
|
||||
|
||||
this.farGrabActive = function () {
|
||||
var farGrab = this.getFarGrab();
|
||||
// farGrab will be null if module isn't loaded.
|
||||
if (farGrab) {
|
||||
return farGrab.targetIsNull();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
this.getOtherHandController = function() {
|
||||
return (this.hand === RIGHT_HAND) ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
|
||||
};
|
||||
|
@ -79,7 +93,7 @@
|
|||
|
||||
this.isReady = function (controllerData) {
|
||||
var otherModuleRunning = this.getOtherModule().running;
|
||||
if (!otherModuleRunning && HMD.active) {
|
||||
if (!otherModuleRunning && HMD.active && !this.farGrabActive()) {
|
||||
if (this.processLaser(controllerData)) {
|
||||
this.running = true;
|
||||
return ControllerDispatcherUtils.makeRunningValues(true, [], []);
|
||||
|
|
|
@ -37,6 +37,20 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
100,
|
||||
makeLaserParams(hand, true));
|
||||
|
||||
this.getFarGrab = function () {
|
||||
return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity"));
|
||||
};
|
||||
|
||||
this.farGrabActive = function () {
|
||||
var farGrab = this.getFarGrab();
|
||||
// farGrab will be null if module isn't loaded.
|
||||
if (farGrab) {
|
||||
return farGrab.targetIsNull();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
this.grabModuleWantsNearbyOverlay = function(controllerData) {
|
||||
if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) {
|
||||
var nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay";
|
||||
|
@ -184,7 +198,12 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
this.dominantHandOverride = false;
|
||||
|
||||
this.isReady = function(controllerData) {
|
||||
this.isReady = function (controllerData) {
|
||||
// Trivial rejection for when FarGrab is active.
|
||||
if (this.farGrabActive()) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
||||
var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE &&
|
||||
controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE;
|
||||
var type = this.getInteractableType(controllerData, isTriggerPressed, false);
|
||||
|
|
|
@ -418,13 +418,11 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride)
|
|||
var HOME_BUTTON_Z_OFFSET = (tabletDepth / 1.9) * sensorScaleOffsetOverride;
|
||||
Entities.editEntity(HMD.homeButtonID, {
|
||||
localPosition: { x: HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
|
||||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||
});
|
||||
|
||||
Entities.editEntity(HMD.homeButtonHighlightID, {
|
||||
localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
|
||||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||
});
|
||||
};
|
||||
|
@ -482,13 +480,11 @@ reparentAndScaleTablet = function(width, reparentProps) {
|
|||
var HOME_BUTTON_Z_OFFSET = (tabletDepth / 1.9) * sensorScaleOffsetOverride;
|
||||
Entities.editEntity(HMD.homeButtonID, {
|
||||
localPosition: { x: HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
|
||||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||
});
|
||||
|
||||
Entities.editEntity(HMD.homeButtonHighlightID, {
|
||||
localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
|
||||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue