Merge branch 'master' of https://github.com/highfidelity/hifi into bugz829

This commit is contained in:
Roxanne Skelly 2019-07-29 10:50:45 -07:00
commit 4722f55c51
109 changed files with 6132 additions and 1399 deletions

View file

@ -66,12 +66,6 @@ Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
Change the Solution Configuration (menu ribbon under the menu bar, next to the green play button) from "Debug" to "Release" for best performance.
Create another environment variable (see Step #3)
* Set "Variable name": `PreferredToolArchitecture`
* Set "Variable value": `x64`
Restart Visual Studio for the new variable to take effect.
Run from the menu bar `Build > Build Solution`.
### Step 6. Testing Interface

View file

@ -10,6 +10,11 @@ endif()
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros/TargetPython.cmake")
target_python()
if (WIN32 AND NOT HIFI_ANDROID)
# Force x64 toolset
set(CMAKE_GENERATOR_TOOLSET "host=x64" CACHE STRING "64-bit toolset" FORCE)
endif()
# set our OS X deployment target
# (needs to be set before first project() call and before prebuild.py)
# Will affect VCPKG dependencies

View file

@ -17,7 +17,7 @@ Documentation
=========
Documentation is available at [docs.highfidelity.com](https://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project).
There is also detailed [documentation on our coding standards](https://wiki.highfidelity.com/wiki/Coding_Standards).
There is also detailed [documentation on our coding standards](CODING_STANDARD.md).
Contributor License Agreement (CLA)
=========

View file

@ -204,10 +204,8 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
if (traitType == AvatarTraits::SkeletonModelURL) {
// special handling for skeleton model URL, since we need to make sure it is in the whitelist
checkSkeletonURLAgainstWhitelist(slaveSharedData, sendingNode, packetTraitVersion);
#ifdef AVATAR_POP_CHECK
// Deferred for UX work. With no PoP check, no need to get the .fst.
_avatar->fetchAvatarFST();
#endif
}
anyTraitsChanged = true;

View file

@ -71,7 +71,7 @@ void MixerAvatar::fetchAvatarFST() {
connect(fstRequest, &ResourceRequest::finished, this, &MixerAvatar::fstRequestComplete);
fstRequest->send();
} else {
qCDebug(avatars) << "Couldn't create FST request for" << avatarURL;
qCDebug(avatars) << "Couldn't create FST request for" << avatarURL << getSessionUUID();
_verifyState = error;
}
_needsIdentityUpdate = true;
@ -84,7 +84,7 @@ void MixerAvatar::fstRequestComplete() {
auto result = fstRequest->getResult();
if (result != ResourceRequest::Success) {
_verifyState = error;
qCDebug(avatars) << "FST request for" << fstRequest->getUrl() << "failed:" << result;
qCDebug(avatars) << "FST request for" << fstRequest->getUrl() << "(user " << getSessionUUID() << ") failed:" << result;
} else {
_avatarFSTContents = fstRequest->getData();
_verifyState = receivedFST;
@ -178,7 +178,8 @@ void MixerAvatar::ownerRequestComplete() {
} else {
auto jsonData = QJsonDocument::fromJson(networkReply->readAll())["data"];
if (!jsonData.isUndefined() && !jsonData.toObject()["message"].isUndefined()) {
qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << ":"
qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << "("
<< getSessionUUID() << ") :"
<< jsonData.toObject()["message"].toString();
_verifyState = error;
_pendingEvent = false;
@ -221,7 +222,7 @@ void MixerAvatar::processCertifyEvents() {
} else {
_needsIdentityUpdate = true;
_pendingEvent = false;
qCDebug(avatars) << "Avatar" << getDisplayName() << "FAILED static certification";
qCDebug(avatars) << "Avatar" << getDisplayName() << "(" << getSessionUUID() << ") FAILED static certification";
}
} else { // FST doesn't have a certificate, so noncertified rather than failed:
_pendingEvent = false;
@ -261,6 +262,8 @@ void MixerAvatar::processCertifyEvents() {
_pendingEvent = true;
} else {
_verifyState = error;
qCDebug(avatars) << "Get owner status - couldn't parse response for" << getSessionUUID()
<< ":" << _dynamicMarketResponse;
}
} else {
qCDebug(avatars) << "Get owner status failed for " << getDisplayName() << _marketplaceIdFromURL <<
@ -332,7 +335,7 @@ void MixerAvatar::sendOwnerChallenge() {
nonceHash.addData(nonce);
_challengeNonceHash = nonceHash.result();
static constexpr int CHALLENGE_TIMEOUT_MS = 5 * 1000; // 5 s
static constexpr int CHALLENGE_TIMEOUT_MS = 10 * 1000; // 10 s
if (_challengeTimeout) {
_challengeTimeout->deleteLater();
}
@ -344,6 +347,7 @@ void MixerAvatar::sendOwnerChallenge() {
_pendingEvent = false;
_verifyState = verificationFailed;
_needsIdentityUpdate = true;
qCDebug(avatars) << "Dynamic verification TIMED-OUT for " << getDisplayName() << getSessionUUID();
}
});
_challengeTimeout->start();

View file

@ -1292,6 +1292,7 @@ void OctreeServer::aboutToFinish() {
for (auto& it : _sendThreads) {
auto& sendThread = *it.second;
sendThread.setIsShuttingDown();
sendThread.terminate();
}
// Clear will destruct all the unique_ptr to OctreeSendThreads which will call the GenericThread's dtor

View file

@ -131,8 +131,11 @@ macro(SET_PACKAGING_PARAMETERS)
endif ()
if (DEPLOY_PACKAGE)
# for deployed packages always grab the serverless content
set(DOWNLOAD_SERVERLESS_CONTENT ON)
# For deployed packages we do not grab the serverless content any longer.
# Instead, we deploy just the serverless content that is in the interface/resources/serverless
# directory. If we ever move back to delivering serverless via a hosted .zip file,
# we can re-enable this.
set(DOWNLOAD_SERVERLESS_CONTENT OFF)
endif ()
if (APPLE)

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -33,33 +33,6 @@ var EventBridge;
// replace the TempEventBridge with the real one.
var tempEventBridge = EventBridge;
EventBridge = channel.objects.eventBridge;
EventBridge.audioOutputDeviceChanged.connect(function(deviceName) {
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function(mediaStream) {
navigator.mediaDevices.enumerateDevices().then(function(devices) {
devices.forEach(function(device) {
if (device.kind == "audiooutput") {
if (device.label == deviceName){
console.log("Changing HTML audio output to device " + device.label);
var deviceId = device.deviceId;
var videos = document.getElementsByTagName("video");
for (var i = 0; i < videos.length; i++){
videos[i].setSinkId(deviceId);
}
var audios = document.getElementsByTagName("audio");
for (var i = 0; i < audios.length; i++){
audios[i].setSinkId(deviceId);
}
}
}
});
}).catch(function(err) {
console.log("Error getting media devices"+ err.name + ": " + err.message);
});
}).catch(function(err) {
console.log("Error getting user media"+ err.name + ": " + err.message);
});
});
// To be able to update the state of the output device selection for every element added to the DOM
// we need to listen to events that might precede the addition of this elements.

View file

@ -14,7 +14,6 @@ Item {
HifiStyles.HifiConstants { id: hifistyles }
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url
property bool canGoBack: webview.canGoBack
@ -30,6 +29,10 @@ Item {
webview.profile = profile;
}
onUrlChanged: {
permissionPopupBackground.visible = false;
}
WebEngineView {
id: webview
objectName: "webEngineView"
@ -84,7 +87,14 @@ Item {
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, false);
if (permissionPopupBackground.visible === true) {
console.log("Browser engine requested a new permission, but user is already being presented with a different permission request. Aborting request for new permission...");
return;
}
permissionPopupBackground.securityOrigin = securityOrigin;
permissionPopupBackground.feature = feature;
permissionPopupBackground.visible = true;
}
onLoadingChanged: {
@ -122,4 +132,11 @@ Item {
break;
}
}
HifiControls.PermissionPopupBackground {
id: permissionPopupBackground
onSendPermission: {
webview.grantFeaturePermission(securityOrigin, feature, shouldGivePermission);
}
}
}

View file

@ -5,4 +5,6 @@ Text {
style: Text.Outline;
styleColor: "black";
font.pixelSize: 12;
font.bold: true;
font.family: "monospace";
}

View file

@ -5,6 +5,7 @@ import QtWebChannel 1.0
import QtQuick.Controls 2.2
import stylesUit 1.0 as StylesUIt
import controlsUit 1.0 as ControlsUit
Item {
id: flick
@ -28,6 +29,10 @@ Item {
property bool blurOnCtrlShift: true
onUrlChanged: {
permissionPopupBackground.visible = false;
}
StylesUIt.HifiConstants {
id: hifi
}
@ -141,7 +146,15 @@ Item {
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, false);
if (permissionPopupBackground.visible === true) {
console.log("Browser engine requested a new permission, but user is already being presented with a different permission request. Aborting request for new permission...");
return;
}
permissionPopupBackground.securityOrigin = securityOrigin;
permissionPopupBackground.feature = feature;
permissionPopupBackground.visible = true;
}
//disable popup
@ -186,4 +199,12 @@ Item {
webViewCore.focus = false;
}
}
ControlsUit.PermissionPopupBackground {
id: permissionPopupBackground
onSendPermission: {
webViewCore.grantFeaturePermission(securityOrigin, feature, shouldGivePermission);
}
}
}

View file

@ -10,10 +10,10 @@
import QtQuick 2.7
import QtWebEngine 1.5
import controlsUit 1.0 as ControlsUit
WebEngineView {
id: root
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")
// Ensure the JS from the web-engine makes it to our logging
@ -22,6 +22,10 @@ WebEngineView {
});
}
onUrlChanged: {
permissionPopupBackground.visible = false;
}
onLoadingChanged: {
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
@ -37,6 +41,21 @@ WebEngineView {
WebSpinner { }
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, false);
if (permissionPopupBackground.visible === true) {
console.log("Browser engine requested a new permission, but user is already being presented with a different permission request. Aborting request for new permission...");
return;
}
permissionPopupBackground.securityOrigin = securityOrigin;
permissionPopupBackground.feature = feature;
permissionPopupBackground.visible = true;
}
ControlsUit.PermissionPopupBackground {
id: permissionPopupBackground
z: 100
onSendPermission: {
root.grantFeaturePermission(securityOrigin, feature, shouldGivePermission);
}
}
}

View file

@ -0,0 +1,90 @@
import QtQuick 2.5
import QtWebEngine 1.5
import QtQuick.Layouts 1.3
import controlsUit 1.0 as HifiControls
import stylesUit 1.0 as HifiStyles
Rectangle {
id: root
width: 750
height: 210
color: hifi.colors.white
anchors.centerIn: parent
readonly property var permissionLanguage: ({
[WebEngineView.MediaAudioCapture]: "access an audio input device",
[WebEngineView.MediaVideoCapture]: "access a video device, like your webcam",
[WebEngineView.MediaAudioVideoCapture]: "access an audio input device and video device",
[WebEngineView.Geolocation]: "access your location",
[WebEngineView.DesktopVideoCapture]: "capture video from your desktop",
[WebEngineView.DesktopAudioVideoCapture]: "capture audio and video from your desktop",
"none": "Undefined permission being requested"
})
property string currentRequestedPermission
signal permissionButtonPressed(int buttonNumber)
ColumnLayout {
anchors.fill: parent
Rectangle {
Layout.preferredHeight: 75
Layout.preferredWidth: parent.width
HifiStyles.RalewayBold {
text: "REQUEST FOR DEVICE ACCESS"
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
wrapMode: Text.WordWrap
color: hifi.colors.black
size: 30
}
}
Rectangle {
Layout.preferredHeight: 35
Layout.preferredWidth: parent.width
HifiStyles.RalewayLight {
text: "This website is attempting to " + root.permissionLanguage[root.currentRequestedPermission] + "."
anchors.centerIn: parent
wrapMode: Text.Wrap
size: 20
color: hifi.colors.black
}
}
Rectangle {
Layout.preferredHeight: 100
Layout.preferredWidth: parent.width
Layout.topMargin: 35
property int space: 8
HifiControls.Button {
text: "Don't Allow"
anchors.right: parent.horizontalCenter
anchors.rightMargin: parent.space
width: 125
color: hifi.buttons.red
height: 38
onClicked: {
root.permissionButtonPressed(0);
}
}
HifiControls.Button {
text: "Yes allow access"
anchors.left: parent.horizontalCenter
anchors.leftMargin: parent.space
color: hifi.buttons.blue
width: 155
height: 38
onClicked: {
root.permissionButtonPressed(1);
}
}
}
}
}

View file

@ -0,0 +1,35 @@
import QtQuick 2.5
Rectangle {
id: root
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.5);
visible: false
property string securityOrigin: 'none'
property string feature: 'none'
signal sendPermission(string securityOrigin, string feature, bool shouldGivePermission)
onFeatureChanged: {
permissionPopupItem.currentRequestedPermission = feature;
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: false
}
PermissionPopup {
id: permissionPopupItem
onPermissionButtonPressed: {
if (buttonNumber === 0) {
root.sendPermission(securityOrigin, feature, false);
} else {
root.sendPermission(securityOrigin, feature, true);
}
root.visible = false;
securityOrigin = 'none';
feature = 'none';
}
}
}

View file

@ -15,6 +15,8 @@ Key 1.0 Key.qml
Keyboard 1.0 Keyboard.qml
Label 1.0 Label.qml
QueuedButton 1.0 QueuedButton.qml
PermissionPopup 1.0 PermissionPopup.qml
PermissionPopupBackground 1.0 PermissionPopupBackground.qml
RadioButton 1.0 RadioButton.qml
ScrollBar 1.0 ScrollBar.qml
Separator 1.0 Separator.qml

View file

@ -39,8 +39,8 @@ Rectangle {
}
Component.onCompleted: {
AudioScriptingInterface.noiseGateOpened.connect(function() { gated = false; });
AudioScriptingInterface.noiseGateClosed.connect(function() { gated = true; });
AudioScriptingInterface.noiseGateOpened.connect(function() { root.gated = false; });
AudioScriptingInterface.noiseGateClosed.connect(function() { root.gated = true; });
HMD.displayModeChanged.connect(function() {
muted = AudioScriptingInterface.muted;
pushToTalk = AudioScriptingInterface.pushToTalk;
@ -151,7 +151,7 @@ Rectangle {
readonly property string yellow: "#C0C000";
readonly property string fill: "#55000000";
readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF";
readonly property string icon: (muted || clipping) ? mutedColor : gated ? gatedColor : unmutedColor;
readonly property string icon: (muted || clipping) ? mutedColor : root.gated ? gatedColor : unmutedColor;
}
Item {
@ -169,7 +169,7 @@ Rectangle {
Image {
id: image;
source: (pushToTalk) ? pushToTalkIcon : muted ? mutedIcon :
clipping ? clippingIcon : gated ? gatedIcon : unmutedIcon;
clipping ? clippingIcon : root.gated ? gatedIcon : unmutedIcon;
width: 29;
height: 32;
anchors {

View file

@ -362,8 +362,8 @@ Rectangle {
id: displayModeImage
source: HMD.active ? "./images/desktopMode.svg" : "./images/vrMode.svg"
anchors.centerIn: parent
width: HMD.active ? 25 : 43
height: 22
width: HMD.active ? 25 : 26
height: HMD.active ? 22 : 14
visible: false
}

File diff suppressed because it is too large Load diff

View file

@ -2824,6 +2824,7 @@ void Application::cleanupBeforeQuit() {
// destroy Audio so it and its threads have a chance to go down safely
// this must happen after QML, as there are unexplained audio crashes originating in qtwebengine
AudioInjector::setLocalAudioInterface(nullptr);
DependencyManager::destroy<AudioClient>();
DependencyManager::destroy<AudioScriptingInterface>();

View file

@ -179,6 +179,18 @@ void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) {
}
}
/**jsdoc
* Details of an avatar bookmark.
* @typedef {object} AvatarBookmarks.BookmarkData
* @property {number} version - The version of the bookmark data format.
* @property {string} avatarUrl - The URL of the avatar model.
* @property {number} avatarScale - The target scale of the avatar.
* @property {Array<Object<"properties",Entities.EntityProperties>>} [avatarEntites] - The avatar entities included with the
* bookmark.
* @property {MyAvatar.AttachmentData[]} [attachments] - The attachments included with the bookmark.
* <p class="important">Deprecated: Use avatar entities instead.
*/
void AvatarBookmarks::loadBookmark(const QString& bookmarkName) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "loadBookmark", Q_ARG(QString, bookmarkName));

View file

@ -16,7 +16,9 @@
#include "Bookmarks.h"
/**jsdoc
* This API helps manage adding and deleting avatar bookmarks.
* The <code>AvatarBookmarks</code> API provides facilities for working with avatar bookmarks ("favorites" in the Avatar app).
* An avatar bookmark associates a name with an avatar model, scale, and avatar entities (wearables).
*
* @namespace AvatarBookmarks
*
* @hifi-interface
@ -32,41 +34,100 @@ class AvatarBookmarks: public Bookmarks, public Dependency {
public:
AvatarBookmarks();
void setupMenus(Menu* menubar, MenuWrapper* menu) override {};
/**jsdoc
* Gets the details of an avatar bookmark.
* @function AvatarBookmarks.getBookmark
* @param {string} bookmarkName - The name of the avatar bookmark (case sensitive).
* @returns {AvatarBookmarks.BookmarkData|{}} The bookmark data if the bookmark exists, <code>{}</code> if it doesn't.
*/
Q_INVOKABLE QVariantMap getBookmark(const QString& bookmarkName);
public slots:
/**jsdoc
* Add the current Avatar to your avatar bookmarks.
* @function AvatarBookmarks.addBookMark
* Adds a new (or updates an existing) avatar bookmark with your current avatar model, scale, and avatar entities.
* @function AvatarBookmarks.addBookmark
* @param {string} bookmarkName - The name of the avatar bookmark (case sensitive).
* @example <caption>Add a new avatar bookmark and report the bookmark data.</caption>
* var bookmarkName = "New Bookmark";
* AvatarBookmarks.addBookmark(bookmarkName);
* var bookmarkData = AvatarBookmarks.getBookmark(bookmarkName);
* print("Bookmark data: " + JSON.stringify(bookmarkData));
*/
void addBookmark(const QString& bookmarkName);
/**jsdoc
* Updates an existing bookmark with your current avatar model, scale, and wearables. No action is taken if the bookmark
* doesn't exist.
* @function AvatarBookmarks.saveBookmark
* @param {string} bookmarkName - The name of the avatar bookmark (case sensitive).
*/
void saveBookmark(const QString& bookmarkName);
/**jsdoc
* Loads an avatar bookmark, setting your avatar model, scale, and avatar entities (or attachments if an old bookmark) to
* those in the bookmark.
* @function AvatarBookmarks.loadBookmark
* @param {string} bookmarkName - The name of the avatar bookmark to load (case sensitive).
*/
void loadBookmark(const QString& bookmarkName);
/**jsdoc
* Deletes an avatar bookmark.
* @function AvatarBookmarks.removeBookmark
* @param {string} bookmarkName - The name of the avatar bookmark to delete (case sensitive).
*/
void removeBookmark(const QString& bookmarkName);
/**jsdoc
* Updates the avatar entities and their properties. Current avatar entities not included in the list provided are deleted.
* @function AvatarBookmarks.updateAvatarEntities
* @param {MyAvatar.AvatarEntityData[]} avatarEntities - The avatar entity IDs and properties.
* @deprecated This function is deprecated and will be removed. Use the {@link MyAvatar} API instead.
*/
void updateAvatarEntities(const QVariantList& avatarEntities);
/**jsdoc
* Gets the details of all avatar bookmarks.
* @function AvatarBookmarks.getBookmarks
* @returns {Object<string,AvatarBookmarks.BookmarkData>} The current avatar bookmarks in an object where the keys are the
* bookmark names and the values are the bookmark details.
* @example <caption>List the names and URLs of all the avatar bookmarks.</caption>
* var bookmarks = AvatarBookmarks.getBookmarks();
* print("Avatar bookmarks:");
* for (var key in bookmarks) {
* print("- " + key + " " + bookmarks[key].avatarUrl);
* };
*/
QVariantMap getBookmarks() { return _bookmarks; }
signals:
/**jsdoc
* This function gets triggered after avatar loaded from bookmark
* Triggered when an avatar bookmark is loaded, setting your avatar model, scale, and avatar entities (or attachments if an
* old bookmark) to those in the bookmark.
* @function AvatarBookmarks.bookmarkLoaded
* @param {string} bookmarkName
* @param {string} bookmarkName - The name of the avatar bookmark loaded.
* @returns {Signal}
*/
void bookmarkLoaded(const QString& bookmarkName);
/**jsdoc
* This function gets triggered after avatar bookmark deleted
* Triggered when an avatar bookmark is deleted.
* @function AvatarBookmarks.bookmarkDeleted
* @param {string} bookmarkName
* @param {string} bookmarkName - The name of the avatar bookmark deleted.
* @returns {Signal}
* @example <caption>Report when a bookmark is deleted.</caption>
* AvatarBookmarks.bookmarkDeleted.connect(function (bookmarkName) {
* print("Bookmark deleted: " + bookmarkName);
* });
*/
void bookmarkDeleted(const QString& bookmarkName);
/**jsdoc
* This function gets triggered after avatar bookmark added
* Triggered when a new avatar bookmark is added or an existing avatar bookmark is updated, using
* {@link AvatarBookmarks.addBookmark|addBookmark}.
* @function AvatarBookmarks.bookmarkAdded
* @param {string} bookmarkName
* @param {string} bookmarkName - The name of the avatar bookmark added or updated.
* @returns {Signal}
*/
void bookmarkAdded(const QString& bookmarkName);
@ -77,6 +138,11 @@ protected:
QVariantMap getAvatarDataToBookmark();
protected slots:
/**jsdoc
* Performs no action.
* @function AvatarBookmarks.deleteBookmark
* @deprecated This function is deprecated and will be removed.
*/
void deleteBookmark() override;
private:

View file

@ -52,6 +52,7 @@ protected:
protected slots:
/**jsdoc
* Prompts the user to delete a bookmark. The user can select the bookmark to delete in the dialog that is opened.
* @function LocationBookmarks.deleteBookmark
*/
virtual void deleteBookmark();

View file

@ -54,6 +54,7 @@ void LODManager::setRenderTimes(float presentTime, float engineRunTime, float ba
}
void LODManager::autoAdjustLOD(float realTimeDelta) {
std::lock_guard<std::mutex> { _automaticLODLock };
// The "render time" is the worse of:
// - engineRunTime: Time spent in the render thread in the engine producing the gpu::Frame N
@ -235,6 +236,7 @@ void LODManager::resetLODAdjust() {
}
void LODManager::setAutomaticLODAdjust(bool value) {
std::lock_guard<std::mutex> { _automaticLODLock };
_automaticLODAdjust = value;
emit autoLODChanged();
}
@ -426,7 +428,6 @@ float LODManager::getWorldDetailQuality() const {
return HIGH;
}
void LODManager::setLODQualityLevel(float quality) {
_lodQualityLevel = quality;
}

View file

@ -12,6 +12,8 @@
#ifndef hifi_LODManager_h
#define hifi_LODManager_h
#include <mutex>
#include <DependencyManager.h>
#include <NumericalConstants.h>
#include <OctreeConstants.h>
@ -47,11 +49,6 @@ class AABox;
* @property {number} presentTime <em>Read-only.</em>
* @property {number} engineRunTime <em>Read-only.</em>
* @property {number} gpuTime <em>Read-only.</em>
* @property {number} avgRenderTime <em>Read-only.</em>
* @property {number} fps <em>Read-only.</em>
* @property {number} lodLevel <em>Read-only.</em>
* @property {number} lodDecreaseFPS <em>Read-only.</em>
* @property {number} lodIncreaseFPS <em>Read-only.</em>
*/
class LODManager : public QObject, public Dependency {
@ -240,6 +237,7 @@ signals:
private:
LODManager();
std::mutex _automaticLODLock;
bool _automaticLODAdjust = true;
float _presentTime{ 0.0f }; // msec

View file

@ -17,6 +17,9 @@
#include "Bookmarks.h"
/**jsdoc
* The <code>LocationBookmarks</code> API provides facilities for working with location bookmarks. A location bookmark
* associates a name with a metaverse address.
*
* @namespace LocationBookmarks
*
* @hifi-client-entity
@ -35,28 +38,35 @@ public:
static const QString HOME_BOOKMARK;
/**jsdoc
* Gets the metaverse address associated with a bookmark.
* @function LocationBookmarks.getAddress
* @param {string} bookmarkName Name of the bookmark to get the address for.
* @returns {string} The url for the specified bookmark. If the bookmark does not exist, the empty string will be returned.
* @param {string} bookmarkName - Name of the bookmark to get the metaverse address for (case sensitive).
* @returns {string} The metaverse address for the bookmark. If the bookmark does not exist, <code>""</code> is returned.
* @example <caption>Report the "Home" bookmark's metaverse address.</caption>
* print("Home bookmark's address: " + LocationBookmarks.getAddress("Home"));
*/
Q_INVOKABLE QString getAddress(const QString& bookmarkName);
public slots:
/**jsdoc
* Prompts the user to bookmark their current location. The user can specify the name of the bookmark in the dialog that is
* opened.
* @function LocationBookmarks.addBookmark
*/
void addBookmark();
/**jsdoc
* Sets the metaverse address associated with the "Home" bookmark.
* @function LocationBookmarks.setHomeLocationToAddress
* @param {string} address
* @param {string} address - The metaverse address to set the "Home" bookmark to.
*/
void setHomeLocationToAddress(const QVariant& address);
/**jsdoc
* Gets the metaverse address associated with the "Home" bookmark.
* @function LocationBookmarks.getHomeLocationAddress
* @returns {string} The url for the home location bookmark
* @returns {string} The metaverse address for the "Home" bookmark.
*/
QString getHomeLocationAddress();

View file

@ -238,7 +238,7 @@ public:
* @function AvatarManager.getPalData
* @param {string[]} [avatarIDs=[]] - The IDs of the avatars to get the PAL data for. If empty, then PAL data is obtained
* for all avatars.
* @returns {object<"data", AvatarManager.PalData[]>} An array of objects, each object being the PAL data for an avatar.
* @returns {Object<"data", AvatarManager.PalData[]>} An array of objects, each object being the PAL data for an avatar.
* @example <caption>Report the PAL data for an avatar nearby.</caption>
* var palData = AvatarManager.getPalData();
* print("PAL data for one avatar: " + JSON.stringify(palData.data[0]));

View file

@ -125,6 +125,18 @@ QString userRecenterModelToString(MyAvatar::SitStandModelType model) {
}
}
static const QStringList REACTION_NAMES = {
QString("positive"),
QString("negative"),
QString("raiseHand"),
QString("applaud"),
QString("point")
};
static int reactionNameToIndex(const QString& reactionName) {
return REACTION_NAMES.indexOf(reactionName);
}
MyAvatar::MyAvatar(QThread* thread) :
Avatar(thread),
_yawSpeed(YAW_SPEED_DEFAULT),
@ -2751,19 +2763,23 @@ QString MyAvatar::getScriptedMotorMode() const {
}
void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) {
float MAX_SCRIPTED_MOTOR_SPEED = 500.0f;
_scriptedMotorVelocity = velocity;
float speed = glm::length(_scriptedMotorVelocity);
if (speed > MAX_SCRIPTED_MOTOR_SPEED) {
_scriptedMotorVelocity *= MAX_SCRIPTED_MOTOR_SPEED / speed;
float newSpeed = glm::length(velocity);
if (!glm::isnan(newSpeed)) {
_scriptedMotorVelocity = velocity;
constexpr float MAX_SCRIPTED_MOTOR_SPEED = 500.0f;
if (newSpeed > MAX_SCRIPTED_MOTOR_SPEED) {
_scriptedMotorVelocity *= MAX_SCRIPTED_MOTOR_SPEED / newSpeed;
}
}
}
void MyAvatar::setScriptedMotorTimescale(float timescale) {
// we clamp the timescale on the large side (instead of just the low side) to prevent
// obnoxiously large values from introducing NaN into avatar's velocity
_scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
if (!glm::isnan(timescale)) {
// we clamp the timescale on the large side (instead of just the low side) to prevent
// obnoxiously large values from introducing NaN into avatar's velocity
_scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
}
}
void MyAvatar::setScriptedMotorFrame(QString frame) {
@ -5808,6 +5824,53 @@ void MyAvatar::setModelScale(float scale) {
}
}
QStringList MyAvatar::getReactions() const {
return REACTION_NAMES;
}
bool MyAvatar::triggerReaction(QString reactionName) {
int reactionIndex = reactionNameToIndex(reactionName);
if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_REACTIONS) {
std::lock_guard<std::mutex> guard(_reactionLock);
_reactionTriggers[reactionIndex] = true;
return true;
}
return false;
}
bool MyAvatar::beginReaction(QString reactionName) {
int reactionIndex = reactionNameToIndex(reactionName);
if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_REACTIONS) {
std::lock_guard<std::mutex> guard(_reactionLock);
_reactionEnabledRefCounts[reactionIndex]++;
return true;
}
return false;
}
bool MyAvatar::endReaction(QString reactionName) {
int reactionIndex = reactionNameToIndex(reactionName);
if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_REACTIONS) {
std::lock_guard<std::mutex> guard(_reactionLock);
_reactionEnabledRefCounts[reactionIndex]--;
return true;
}
return false;
}
void MyAvatar::updateRigControllerParameters(Rig::ControllerParameters& params) {
std::lock_guard<std::mutex> guard(_reactionLock);
for (int i = 0; i < NUM_AVATAR_REACTIONS; i++) {
// copy current state into params.
params.reactionEnabledFlags[i] = _reactionEnabledRefCounts[i] > 0;
params.reactionTriggers[i] = _reactionTriggers[i];
// clear reaction triggers here as well
_reactionTriggers[i] = false;
}
}
SpatialParentTree* MyAvatar::getParentTree() const {
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
@ -6144,3 +6207,51 @@ void MyAvatar::sendPacket(const QUuid& entityID) const {
});
}
}
void MyAvatar::setSitDriveKeysStatus(bool enabled) {
const std::vector<DriveKeys> DISABLED_DRIVE_KEYS_DURING_SIT = {
DriveKeys::TRANSLATE_X,
DriveKeys::TRANSLATE_Y,
DriveKeys::TRANSLATE_Z,
DriveKeys::STEP_TRANSLATE_X,
DriveKeys::STEP_TRANSLATE_Y,
DriveKeys::STEP_TRANSLATE_Z
};
for (auto key : DISABLED_DRIVE_KEYS_DURING_SIT) {
if (enabled) {
enableDriveKey(key);
} else {
disableDriveKey(key);
}
}
}
void MyAvatar::beginSit(const glm::vec3& position, const glm::quat& rotation) {
_characterController.setSeated(true);
setCollisionsEnabled(false);
setHMDLeanRecenterEnabled(false);
// Disable movement
setSitDriveKeysStatus(false);
centerBody();
int hipIndex = getJointIndex("Hips");
clearPinOnJoint(hipIndex);
goToLocation(position, true, rotation, false, false);
pinJoint(hipIndex, position, rotation);
}
void MyAvatar::endSit(const glm::vec3& position, const glm::quat& rotation) {
if (_characterController.getSeated()) {
clearPinOnJoint(getJointIndex("Hips"));
_characterController.setSeated(false);
setCollisionsEnabled(true);
setHMDLeanRecenterEnabled(true);
centerBody();
goToLocation(position, true, rotation, false, false);
float TIME_BEFORE_DRIVE_ENABLED_MS = 150.0f;
QTimer::singleShot(TIME_BEFORE_DRIVE_ENABLED_MS, [this]() {
// Enable movement again
setSitDriveKeysStatus(true);
});
}
}

View file

@ -1369,9 +1369,9 @@ public:
bool hasDriveInput() const;
/**jsdoc
* Gets the list of avatar entities and their properties.
* Gets the current avatar entity IDs and their properties.
* @function MyAvatar.getAvatarEntitiesVariant
* @returns {MyAvatar.AvatarEntityData[]} The list of avatar entities and their properties.
* @returns {MyAvatar.AvatarEntityData[]} The current avatar entity IDs and their properties.
*/
Q_INVOKABLE QVariantList getAvatarEntitiesVariant();
@ -1835,10 +1835,30 @@ public:
*/
Q_INVOKABLE QVariantList getCollidingFlowJoints();
/**jsdoc
* Starts a sitting action for the avatar
* @function MyAvatar.beginSit
* @param {Vec3} position - The point in space where the avatar will sit.
* @param {Quat} rotation - Initial absolute orientation of the avatar once is seated.
*/
Q_INVOKABLE void beginSit(const glm::vec3& position, const glm::quat& rotation);
/**jsdoc
* Ends a sitting action for the avatar
* @function MyAvatar.endSit
* @param {Vec3} position - The position of the avatar when standing up.
* @param {Quat} rotation - The absolute rotation of the avatar once the sitting action ends.
*/
Q_INVOKABLE void endSit(const glm::vec3& position, const glm::quat& rotation);
int getOverrideJointCount() const;
bool getFlowActive() const;
bool getNetworkGraphActive() const;
// sets the reaction enabled and triggered parameters of the passed in params
// also clears internal reaction triggers
void updateRigControllerParameters(Rig::ControllerParameters& params);
public slots:
/**jsdoc
@ -2192,6 +2212,33 @@ public slots:
*/
virtual void setModelScale(float scale) override;
/**jsdoc
* MyAvatar.getReactions
* @returns {string[]} Array of reaction names.
*/
QStringList getReactions() const;
/**jsdoc
* MyAvatar.triggerReaction
* @param {string} reactionName - reaction name
* @returns {bool} false if the given reaction is not supported.
*/
bool triggerReaction(QString reactionName);
/**jsdoc
* MyAvatar.beginReaction
* @param {string} reactionName - reaction name
* @returns {bool} false if the given reaction is not supported.
*/
bool beginReaction(QString reactionName);
/**jsdoc
* MyAvatar.endReaction
* @param {string} reactionName - reaction name
* @returns {bool} false if the given reaction is not supported.
*/
bool endReaction(QString reactionName);
signals:
/**jsdoc
@ -2490,6 +2537,7 @@ private:
virtual void updatePalms() override {}
void lateUpdatePalms();
void setSitDriveKeysStatus(bool enabled);
void clampTargetScaleToDomainLimits();
void clampScaleChangeToDomainLimits(float desiredScale);
@ -2823,6 +2871,10 @@ private:
mutable std::mutex _scriptEngineLock;
QScriptEngine* _scriptEngine { nullptr };
bool _needToSaveAvatarEntitySettings { false };
int _reactionEnabledRefCounts[NUM_AVATAR_REACTIONS] { 0, 0, 0, 0, 0 };
bool _reactionTriggers[NUM_AVATAR_REACTIONS] { false, false, false, false, false };
mutable std::mutex _reactionLock;
};
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);

View file

@ -32,6 +32,8 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle
return Rig::CharacterControllerState::InAir;
case CharacterController::State::Hover:
return Rig::CharacterControllerState::Hover;
case CharacterController::State::Seated:
return Rig::CharacterControllerState::Seated;
};
}
@ -294,8 +296,6 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_prevIsEstimatingHips = false;
}
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
// pass detailed torso k-dops to rig.
int hipsJoint = _rig.indexOfJoint("Hips");
if (hipsJoint >= 0) {
@ -314,6 +314,10 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
params.spine2ShapeInfo = hfmModel.joints[spine2Joint].shapeInfo;
}
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
myAvatar->updateRigControllerParameters(params);
_rig.updateFromControllerParameters(params, deltaTime);
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());

View file

@ -29,7 +29,7 @@
* @property {FilterFlags} PICK_AVATAR_ENTITIES - Include avatar entities when intersecting. <em>Read-only.</em>
* @property {FilterFlags} PICK_LOCAL_ENTITIES - Include local entities when intersecting. <em>Read-only.</em>
* @property {FilterFlags} PICK_AVATARS - Include avatars when intersecting. <em>Read-only.</em>
* @property {FilterFlags} PICK_HUD - Include the HUD sphere when intersecting in HMD mode. <em>Read-only.</em>
* @property {FilterFlags} PICK_HUD - Include the HUD surface when intersecting in HMD mode. <em>Read-only.</em>
*
* @property {FilterFlags} PICK_ENTITIES - Include domain and avatar entities when intersecting. <em>Read-only.</em>
* <p class="important">Deprecated: This property is deprecated and will be removed. Use <code>PICK_DOMAIN_ENTITIES |
@ -61,7 +61,7 @@
* <p class="important">Deprecated: This property is deprecated and will be removed. Use
* <code>INTERSECTED_LOCAL_ENTITY</code> instead.</p>
* @property {IntersectionType} INTERSECTED_AVATAR - Intersected an avatar. <em>Read-only.</em>
* @property {IntersectionType} INTERSECTED_HUD - Intersected the HUD sphere. <em>Read-only.</em>
* @property {IntersectionType} INTERSECTED_HUD - Intersected the HUD surface. <em>Read-only.</em>
*
* @property {number} perFrameTimeBudget - The maximum time, in microseconds, to spend per frame updating pick results.
*/

View file

@ -33,7 +33,7 @@
* <em>Read-only.</em>
* @property {FilterFlags} PICK_OVERLAYS - Include local entities when intersecting. <em>Read-only.</em>
* @property {FilterFlags} PICK_AVATARS - Include avatars when intersecting. <em>Read-only.</em>
* @property {FilterFlags} PICK_HUD - Include the HUD sphere when intersecting in HMD mode. <em>Read-only.</em>
* @property {FilterFlags} PICK_HUD - Include the HUD surface when intersecting in HMD mode. <em>Read-only.</em>
* @property {FilterFlags} PICK_PRECISE - Pick against exact meshes. <em>Read-only.</em>
* @property {FilterFlags} PICK_INCLUDE_INVISIBLE - Include invisible objects when intersecting. <em>Read-only.</em>
* @property {FilterFlags} PICK_INCLUDE_NONCOLLIDABLE - Include non-collidable objects when intersecting. <em>Read-only.</em>
@ -43,7 +43,7 @@
* @property {IntersectionType} INTERSECTED_LOCAL_ENTITY - Intersected a local entity. <em>Read-only.</em>
* @property {IntersectionType} INTERSECTED_OVERLAY - Intersected an entity (3D Overlays no longer exist). <em>Read-only.</em>
* @property {IntersectionType} INTERSECTED_AVATAR - Intersected an avatar. <em>Read-only.</em>
* @property {IntersectionType} INTERSECTED_HUD - Intersected the HUD sphere. <em>Read-only.</em>
* @property {IntersectionType} INTERSECTED_HUD - Intersected the HUD surface. <em>Read-only.</em>
*/
class RayPickScriptingInterface : public QObject, public Dependency {
Q_OBJECT

View file

@ -459,7 +459,7 @@ signals:
/**jsdoc
* Triggered when the server injector gain changes.
* @function Audio.serverInjectorGainChanged
* @param {float} gain - The new server injector gain value.
* @param {number} gain - The new server injector gain value.
* @returns {Signal}
*/
void serverInjectorGainChanged(float gain);

View file

@ -62,7 +62,7 @@ class QScriptEngine;
* @property {Uuid} miniTabletScreenID - The UUID of the mini tablet's screen entity. <code>null</code> if not in HMD mode.
* @property {number} miniTabletHand - The hand that the mini tablet is displayed on: <code>0</code> for left hand,
* <code>1</code> for right hand, <code>-1</code> if not in HMD mode.
* @property {bool} miniTabletEnabled=true - <code>true</code> if the mini tablet is enabled to be displayed, otherwise
* @property {boolean} miniTabletEnabled=true - <code>true</code> if the mini tablet is enabled to be displayed, otherwise
* <code>false</code>.
* @property {Rect} playArea=0,0,0,0 - The size and position of the HMD play area in sensor coordinates. <em>Read-only.</em>
* @property {Vec3[]} sensorPositions=[]] - The positions of the VR system sensors in sensor coordinates. <em>Read-only.</em>

View file

@ -658,7 +658,8 @@ signals:
/**jsdoc
* Triggered when you try to visit a domain but are redirected into the error state.
* @function Window.redirectErrorStateChanged
* @param {boolean} isInErrorState - If <code>true</code>, the user has been redirected to the error URL.
* @param {boolean} isInErrorState - <code>true</code> if the user has been redirected to the error URL, <code>false</code>
* if they haven't.
* @returns {Signal}
*/
void redirectErrorStateChanged(bool isInErrorState);
@ -666,8 +667,8 @@ signals:
/**jsdoc
* Triggered when the interstitial mode changes.
* @function Window.interstitialModeChanged
* @param {bool} interstitialMode - The new interstitial mode value. If <code>true</code>, the interstitial graphics are
* displayed when the domain is loading.
* @param {boolean} interstitialMode - <code>true</code> if the interstitial graphics are displayed when the domain is
* loading, <code>false</code> if they are not.
* @returns {Signal}
*/
void interstitialModeChanged(bool interstitialMode);

View file

@ -24,18 +24,31 @@ class AvatarInputs : public QObject {
HIFI_QML_DECL
/**jsdoc
* API to help manage your Avatar's input
* The <code>AvatarInputs</code> API provides facilities to manage user inputs.
*
* @namespace AvatarInputs
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {boolean} cameraEnabled <em>Read-only.</em>
* @property {boolean} cameraMuted <em>Read-only.</em>
* @property {boolean} isHMD <em>Read-only.</em>
* @property {boolean} showAudioTools
* @property {boolean} showBubbleTools
* @property {boolean} cameraEnabled - <code>true</code> if webcam face tracking is enabled, <code>false</code> if it is
* disabled.
* <em>Read-only.</em>
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {boolean} cameraMuted - <code>true</code> if webcam face tracking is muted (temporarily disabled),
* <code>false</code> it if isn't.
* <em>Read-only.</em>
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {boolean} ignoreRadiusEnabled - <code>true</code> if the privacy shield is enabled, <code>false</code> if it
* is disabled.
* <em>Read-only.</em>
* @property {boolean} isHMD - <code>true</code> if the display mode is HMD, <code>false</code> if it isn't.
* <em>Read-only.</em>
* @property {boolean} showAudioTools - <code>true</code> if the microphone mute button and audio level meter are shown,
* <code>false</code> if they are hidden.
* @property {boolean} showBubbleTools - <code>true</code> if the privacy shield UI button is shown, <code>false</code> if
* it is hidden.
*/
AI_PROPERTY(bool, cameraEnabled, false)
@ -51,9 +64,10 @@ public:
static AvatarInputs* getInstance();
/**jsdoc
* Converts non-linear audio loudness to a linear audio level.
* @function AvatarInputs.loudnessToAudioLevel
* @param {number} loudness
* @returns {number}
* @param {number} loudness - The non-linear audio loudness.
* @returns {number} The linear audio level.
*/
Q_INVOKABLE float loudnessToAudioLevel(float loudness);
@ -67,76 +81,96 @@ public:
public slots:
/**jsdoc
* Sets whether or not the microphone mute button and audio level meter is shown.
* @function AvatarInputs.setShowAudioTools
* @param {boolean} showAudioTools
* @param {boolean} showAudioTools - <code>true</code> to show the microphone mute button and audio level meter,
* <code>false</code> to hide it.
*/
void setShowAudioTools(bool showAudioTools);
/**jsdoc
* Sets whether or not the privacy shield button is shown.
* @function AvatarInputs.setShowBubbleTools
* @param {boolean} showBubbleTools
* @param {boolean} showBubbleTools - <code>true</code> to show the privacy shield button, <code>false</code> to hide it.
*/
void setShowBubbleTools(bool showBubbleTools);
signals:
/**jsdoc
* Triggered when webcam face tracking is enabled or disabled.
* @deprecated This signal is deprecated and will be removed.
* @function AvatarInputs.cameraEnabledChanged
* @returns {Signal}
*/
void cameraEnabledChanged();
/**jsdoc
* Triggered when webcam face tracking is muted (temporarily disabled) or unmuted.
* @deprecated This signal is deprecated and will be removed.
* @function AvatarInputs.cameraMutedChanged
* @returns {Signal}
*/
void cameraMutedChanged();
/**jsdoc
* Triggered when the display mode changes between desktop and HMD.
* @function AvatarInputs.isHMDChanged
* @returns {Signal}
*/
void isHMDChanged();
/**jsdoc
* Triggered when the visibility of the microphone mute button and audio level meter changes.
* @function AvatarInputs.showAudioToolsChanged
* @param {boolean} show
* @param {boolean} show - <code>true</code> if the microphone mute button and audio level meter are shown,
* <code>false</code> if they are is hidden.
* @returns {Signal}
*/
void showAudioToolsChanged(bool show);
/**jsdoc
* Triggered when the visibility of the privacy shield button changes.
* @function AvatarInputs.showBubbleToolsChanged
* @param {boolean} show
* @param {boolean} show - <code>true</code> if the privacy shield UI button is shown, <code>false</code> if
* it is hidden.
* @returns {Signal}
*/
void showBubbleToolsChanged(bool show);
/**jsdoc
* Triggered when another user enters the privacy shield.
* @function AvatarInputs.avatarEnteredIgnoreRadius
* @param {QUuid} avatarID
* @param {QUuid} avatarID - The session ID of the user that entered the privacy shield.
* @returns {Signal}
*/
* @example <caption>Report when a user enters the privacy shield.</caption>
* AvatarInputs.avatarEnteredIgnoreRadius.connect(function(avatarID) {
* print("User entered the privacy shield: " + avatarID);
* };
*/
void avatarEnteredIgnoreRadius(QUuid avatarID);
/**jsdoc
* Triggered when another user leaves the privacy shield.
* <p><strong>Note:</strong> Currently doesn't work.</p>
* @function AvatarInputs.avatarLeftIgnoreRadius
* @param {QUuid} avatarID
* @param {QUuid} avatarID - The session ID of the user that exited the privacy shield.
* @returns {Signal}
*/
* @deprecated This signal is deprecated and will be removed.
*/
void avatarLeftIgnoreRadius(QUuid avatarID);
/**jsdoc
* Triggered when the privacy shield is enabled or disabled.
* @function AvatarInputs.ignoreRadiusEnabledChanged
* @param {boolean} enabled
* @param {boolean} enabled - <code>true</code> if the privacy shield is enabled, <code>false</code> if it is disabled.
* @returns {Signal}
*/
void ignoreRadiusEnabledChanged(bool enabled);
/**jsdoc
* Triggered when another user enters the privacy shield.
* @function AvatarInputs.enteredIgnoreRadiusChanged
* @param {boolean} enabled
* @returns {Signal}
*/
void enteredIgnoreRadiusChanged();
@ -144,11 +178,14 @@ signals:
protected:
/**jsdoc
* Resets sensors, audio, avatar animations, and the avatar rig.
* @function AvatarInputs.resetSensors
*/
Q_INVOKABLE void resetSensors();
/**jsdoc
* Toggles the muting (temporary disablement) of webcam face tracking on/off.
* <p class="important">Deprecated: This function is deprecated and will be removed.</p>
* @function AvatarInputs.toggleCameraMute
*/
Q_INVOKABLE void toggleCameraMute();

View file

@ -69,6 +69,14 @@ void QmlWindowProxy::parentNativeWindowToMainWindow() {
#endif
}
void InteractiveWindowProxy::emitScriptEvent(const QVariant& scriptMessage){
emit scriptEventReceived(scriptMessage);
}
void InteractiveWindowProxy::emitWebEvent(const QVariant& webMessage) {
emit webEventReceived(webMessage);
}
static void qmlWindowProxyDeleter(QmlWindowProxy* qmlWindowProxy) {
qmlWindowProxy->deleteLater();
}
@ -129,6 +137,12 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
presentationMode = (InteractiveWindowPresentationMode) properties[PRESENTATION_MODE_PROPERTY].toInt();
}
if (!_interactiveWindowProxy) {
_interactiveWindowProxy = new InteractiveWindowProxy();
QObject::connect(_interactiveWindowProxy, &InteractiveWindowProxy::webEventReceived, this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection);
QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy, &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection);
}
if (properties.contains(DOCKED_PROPERTY) && presentationMode == InteractiveWindowPresentationMode::Native) {
QVariantMap nativeWindowInfo = properties[DOCKED_PROPERTY].toMap();
Qt::DockWidgetArea dockArea = Qt::TopDockWidgetArea;
@ -182,13 +196,17 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
break;
}
}
QObject::connect(quickView.get(), &QQuickView::statusChanged, [&, this] (QQuickView::Status status) {
if (status == QQuickView::Ready) {
QQuickItem* rootItem = _dockWidget->getRootItem();
_dockWidget->getQuickView()->rootContext()->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
_dockWidget->getQuickView()->rootContext()->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy);
// The qmlToScript method handles the thread-safety of this call. Because the QVariant argument
// passed to the sendToScript signal may wrap an externally managed and thread-unsafe QJSValue,
// qmlToScript needs to be called directly, so the QJSValue can be immediately converted to a plain QVariant.
QObject::connect(rootItem, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)),
Qt::QueuedConnection);
Qt::DirectConnection);
QObject::connect(rootItem, SIGNAL(keyPressEvent(int, int)), this, SLOT(forwardKeyPressEvent(int, int)),
Qt::QueuedConnection);
QObject::connect(rootItem, SIGNAL(keyReleaseEvent(int, int)), this, SLOT(forwardKeyReleaseEvent(int, int)),
@ -204,7 +222,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
// Build the event bridge and wrapper on the main thread
offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) {
_qmlWindowProxy = std::shared_ptr<QmlWindowProxy>(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter);
context->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy);
if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) {
object->setProperty(ADDITIONAL_FLAGS_PROPERTY, properties[ADDITIONAL_FLAGS_PROPERTY].toUInt());
}
@ -229,7 +247,10 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
object->setProperty(VISIBLE_PROPERTY, properties[INTERACTIVE_WINDOW_VISIBLE_PROPERTY].toBool());
}
connect(object, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::QueuedConnection);
// The qmlToScript method handles the thread-safety of this call. Because the QVariant argument
// passed to the sendToScript signal may wrap an externally managed and thread-unsafe QJSValue,
// qmlToScript needs to be called directly, so the QJSValue can be immediately converted to a plain QVariant.
connect(object, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::DirectConnection);
QObject::connect(object, SIGNAL(keyPressEvent(int, int)), this, SLOT(forwardKeyPressEvent(int, int)),
Qt::QueuedConnection);
QObject::connect(object, SIGNAL(keyReleaseEvent(int, int)), this, SLOT(forwardKeyReleaseEvent(int, int)),
@ -263,6 +284,7 @@ InteractiveWindow::~InteractiveWindow() {
}
void InteractiveWindow::sendToQml(const QVariant& message) {
// Forward messages received from the script on to QML
if (_dockWidget) {
QQuickItem* rootItem = _dockWidget->getRootItem();
@ -291,6 +313,10 @@ void InteractiveWindow::close() {
_qmlWindowProxy->deleteLater();
}
if (_interactiveWindowProxy) {
_interactiveWindowProxy->deleteLater();
}
if (_dockWidget) {
auto window = qApp->getWindow();
if (QThread::currentThread() != window->thread()) {
@ -301,6 +327,7 @@ void InteractiveWindow::close() {
}
_dockWidget = nullptr;
_qmlWindowProxy = nullptr;
_interactiveWindowProxy = nullptr;
}
void InteractiveWindow::show() {
@ -315,13 +342,21 @@ void InteractiveWindow::raise() {
}
}
void InteractiveWindow::qmlToScript(const QVariant& message) {
void InteractiveWindow::qmlToScript(const QVariant& originalMessage) {
QVariant message = originalMessage;
if (message.canConvert<QJSValue>()) {
emit fromQml(qvariant_cast<QJSValue>(message).toVariant());
message = qvariant_cast<QJSValue>(message).toVariant();
} else if (message.canConvert<QString>()) {
emit fromQml(message.toString());
message = message.toString();
} else {
qWarning() << "Unsupported message type " << message;
return;
}
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "fromQml", Q_ARG(const QVariant&, message));
} else {
emit fromQml(message);
}
}

View file

@ -34,7 +34,23 @@ public:
QObject* getQmlWindow() const { return _qmlWindow; }
private:
QObject* _qmlWindow;
};
class InteractiveWindowProxy : public QObject {
Q_OBJECT
public:
InteractiveWindowProxy(){}
public slots:
void emitScriptEvent(const QVariant& scriptMessage);
void emitWebEvent(const QVariant& webMessage);
signals:
void scriptEventReceived(const QVariant& message);
void webEventReceived(const QVariant& message);
};
@ -309,6 +325,7 @@ protected slots:
private:
std::shared_ptr<QmlWindowProxy> _qmlWindowProxy;
std::shared_ptr<DockWidget> _dockWidget { nullptr };
InteractiveWindowProxy *_interactiveWindowProxy{ nullptr };
};
typedef InteractiveWindow* InteractiveWindowPointer;

View file

@ -1333,127 +1333,170 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <p>An overlay may be one of the following types:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>2D/3D</th><th>Description</th></tr>
* <tr><th>Value</th><th>2D/3D</th><th>Description</th><th>Properties</th></tr>
* </thead>
* <tbody>
* <tr><td><code>image</code></td><td>2D</td><td>An image. Synonym: <code>billboard</code>.</td></tr>
* <tr><td><code>rectangle</code></td><td>2D</td><td>A rectangle.</td></tr>
* <tr><td><code>text</code></td><td>2D</td><td>Text.</td></tr>
* <tr><td><code>cube</code></td><td>3D</td><td>A cube. Can also use a <code>shape</code> overlay to create a cube.</td></tr>
* <tr><td><code>sphere</code></td><td>3D</td><td>A sphere. Can also use a <code>shape</code> overlay to create a sphere.</td></tr>
* <tr><td><code>rectangle3d</code></td><td>3D</td><td>A rectangle.</td></tr>
* <tr><td><code>shape</code></td><td>3D</td><td>A geometric shape, such as a cube, sphere, or cylinder.</td></tr>
* <tr><td><code>model</code></td><td>3D</td><td>A model.</td></tr>
* <tr><td><code>text3d</code></td><td>3D</td><td>Text.</td></tr>
* <tr><td><code>image3d</code></td><td>3D</td><td>An image.</td></tr>
* <tr><td><code>web3d</code></td><td>3D</td><td>Web content.</td></tr>
* <tr><td><code>line3d</code></td><td>3D</td><td>A line.</td></tr>
* <tr><td><code>grid</code></td><td>3D</td><td>A grid of lines in a plane.</td></tr>
* <tr><td><code>circle3d</code></td><td>3D</td><td>A circle.</td></tr>
* <tr><td><code>"rectangle"</code></td><td>2D</td>
* <td>A rectangle.</td>
* <td>{@link Overlays.OverlayProperties-Rectangle|OverlayProperties-Rectangle}</td></tr>
* <tr><td><code>"image"</code></td><td>2D</td>
* <td>An image.</td>
* <td>{@link Overlays.OverlayProperties-Image|OverlayProperties-Image}</td></tr>
* <tr><td><code>"text"</code></td><td>2D</td>
* <td>Some text.</td>
* <td>{@link Overlays.OverlayProperties-Text|OverlayProperties-Text}</td></tr>
* <tr><td><code>"cube"</code></td><td>3D</td>
* <td>A cube. A <code>"shape"</code> overlay can also be used to create a cube.<br/>
* <span class="important">Deprecated.</span>
* </td>
* <td>{@link Overlays.OverlayProperties-Cube|OverlayProperties-Cube}</td></tr>
* <tr><td><code>"sphere"</code></td><td>3D</td>
* <td>A sphere. A <code>"shape"</code> overlay can also be used to create a sphere.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Sphere|OverlayProperties-Sphere}</td></tr>
* <tr><td><code>"shape"</code></td><td>3D</td>
* <td>A geometric shape, such as a cube, sphere, or cylinder.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Shape|OverlayProperties-Shape}</td></tr>
* <tr><td><code>"model"</code></td><td>3D</td>
* <td>A model.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Model|OverlayProperties-Model}</td></tr>
* <tr><td><code>"image3d"</code></td><td>3D</td>
* <td>An image. Synonym: <code>"billboard"</code>.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Image3D|OverlayProperties-Image3D}</td></tr>
* <tr><td><code>"rectangle3d"</code></td><td>3D</td>
* <td>A rectangle.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Rectangle3D|OverlayProperties-Rectangle3D}</td></tr>
* <tr><td><code>"text3d"</code></td><td>3D</td>
* <td>Some text.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Text3D|OverlayProperties-Text3D}</td></tr>
* <tr><td><code>"web3d"</code></td><td>3D</td>
* <td>Web content.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Web3D|OverlayProperties-Web3D}</td></tr>
* <tr><td><code>"line3d"</code></td><td>3D</td>
* <td>A line.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Line3D|OverlayProperties-Line3D}</td></tr>
* <tr><td><code>"grid"</code></td><td>3D</td>
* <td>A grid of lines in a plane.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Grid|OverlayProperties-Grid}</td></tr>
* <tr><td><code>"circle3d"</code></td><td>3D</td>
* <td>A circle.<br/>
* <span class="important">Deprecated.</span></td>
* <td>{@link Overlays.OverlayProperties-Circle3D|OverlayProperties-Circle3D}</td></tr>
* </tbody>
* </table>
* <p>2D overlays are rendered on the display surface in desktop mode and on the HUD surface in HMD mode. 3D overlays are
* rendered at a position and orientation in-world, but are deprecated (use local entities instead).<p>
* <p>Each overlay type has different {@link Overlays.OverlayProperties|OverlayProperties}.</p>
* rendered at a position and orientation in-world.</p>
* <p class="important">3D overlays are deprecated. Use local {@link Entities} instead.</p>
* @typedef {string} Overlays.OverlayType
*/
/**jsdoc
* Different overlay types have different properties: some common to all overlays (listed below) and some specific to each
* {@link Overlays.OverlayType|OverlayType} (linked to below). The properties are accessed as an object of property names and
* values. 3D Overlays are local entities, internally, so they also support the corresponding entity properties.
*
* Different overlay types have different properties: some common to all overlays (listed in the table) and some specific to
* each {@link Overlays.OverlayType|OverlayType} (linked to below).
* <p>3D overlays are local entities, internally, so they also support the relevant entity's properties.</p>
* @typedef {object} Overlays.OverlayProperties
* @property {Uuid} id - The ID of the overlay. <em>Read-only.</em>
* @property {Overlays.OverlayType} type - The overlay type. <em>Read-only.</em>
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
* @property {Overlays.OverlayType} type - The overlay's type. <em>Read-only.</em>
* @property {boolean} visible=true - <code>true</code> if the overlay is rendered, <code>false</code> if it isn't.
*
* @see The different entity types have additional properties as follows:
* @see {@link Overlays.OverlayProperties-Rectangle|OverlayProperties-Rectangle}
* @see {@link Overlays.OverlayProperties-Image|OverlayProperties-Image}
* @see {@link Overlays.OverlayProperties-Text|OverlayProperties-Text}
* @see {@link Overlays.OverlayProperties-Rectangle|OverlayProperties-Rectangle}
* @see {@link Overlays.OverlayProperties-Cube|OverlayProperties-Cube}
* @see {@link Overlays.OverlayProperties-Sphere|OverlayProperties-Sphere}
* @see {@link Overlays.OverlayProperties-Rectangle3D|OverlayProperties-Rectangle3D}
* @see {@link Overlays.OverlayProperties-Shape|OverlayProperties-Shape}
* @see {@link Overlays.OverlayProperties-Model|OverlayProperties-Model}
* @see {@link Overlays.OverlayProperties-Text3D|OverlayProperties-Text3D}
* @see {@link Overlays.OverlayProperties-Image3D|OverlayProperties-Image3D}
* @see {@link Overlays.OverlayProperties-Web|OverlayProperties-Web}
* @see {@link Overlays.OverlayProperties-Line|OverlayProperties-Line}
* @see {@link Overlays.OverlayProperties-Grid|OverlayProperties-Grid}
* @see {@link Overlays.OverlayProperties-Circle|OverlayProperties-Circle}
* @see {@link Overlays.OverlayProperties-Cube|OverlayProperties-Cube} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Sphere|OverlayProperties-Sphere} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Shape|OverlayProperties-Shape} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Model|OverlayProperties-Model} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Rectangle3D|OverlayProperties-Rectangle3D} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Image3D|OverlayProperties-Image3D} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Text3D|OverlayProperties-Text3D} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Web3D|OverlayProperties-Web3D} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Line3D|OverlayProperties-Line3D} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Grid|OverlayProperties-Grid} <span class="important">Deprecated.</span>
* @see {@link Overlays.OverlayProperties-Circle3D|OverlayProperties-Circle3D} <span class="important">Deprecated.</span>
*/
/**jsdoc
* The <code>"Image"</code> {@link Overlays.OverlayType|OverlayType} is a 2D image.
* The <code>"image"</code> {@link Overlays.OverlayType|OverlayType} is for 2D images.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* @typedef {object} Overlays.OverlayProperties-Image
* @property {Rect} bounds - The position and size of the image display area, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value of the image display area = <code>bounds.x</code>.
* <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value of the image display area = <code>bounds.y</code>.
* @property {number} y - Integer top, y-coordinate value of the image display area = <code>bounds.y</code>.
* <em>Write-only.</em>
* @property {number} width - Integer width of the image display area = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the image display area = <code>bounds.height</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the image display area = <code>bounds.height</code>. <em>Write-only.</em>
* @property {string} imageURL - The URL of the image file to display. The image is scaled to fit to the <code>bounds</code>.
* <em>Write-only.</em>
* @property {Vec2} subImage=0,0 - Integer coordinates of the top left pixel to start using image content from.
* @property {Rect} subImage - The portion of the image to use. If not specified, the whole image is used.
* <em>Write-only.</em>
* @property {Color} color=0,0,0 - The color to apply over the top of the image to colorize it. <em>Write-only.</em>
* @property {number} alpha=0.0 - The opacity of the color applied over the top of the image, <code>0.0</code> -
* @property {number} alpha=0.0 - The opacity of the color applied over the top of the image, <code>0.0</code> &ndash;
* <code>1.0</code>. <em>Write-only.</em>
*/
/**jsdoc
* The <code>"Text"</code> {@link Overlays.OverlayType|OverlayType} is for 2D text.
* The <code>"text"</code> {@link Overlays.OverlayType|OverlayType} is for 2D text.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* @typedef {object} Overlays.OverlayProperties-Text
* @property {Rect} bounds - The position and size of the rectangle, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value = <code>bounds.x</code>. <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value = <code>bounds.y</code>. <em>Write-only.</em>
* @property {number} width - Integer width of the rectangle = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the rectangle = <code>bounds.height</code>. <em>Write-only.</em>
*
* @property {number} margin=0 - Sets the <code>leftMargin</code> and <code>topMargin</code> values, in pixels.
* @property {number} margin=0 - The <code>leftMargin</code> and <code>topMargin</code> values, in pixels.
* <em>Write-only.</em>
* @property {number} leftMargin=0 - The left margin's size, in pixels. This value is also used for the right margin.
* <em>Write-only.</em>
* @property {number} topMargin=0 - The top margin's size, in pixels. This value is also used for the bottom margin.
* <em>Write-only.</em>
* @property {string} text="" - The text to display. Text does not automatically wrap; use <code>\n</code> for a line break. Text
* is clipped to the <code>bounds</code>. <em>Write-only.</em>
* @property {string} text="" - The text to display. Text does not automatically wrap; use <code>"\n"</code> for a line break.
* Text is clipped to the <code>bounds</code>. <em>Write-only.</em>
* @property {number} font.size=18 - The size of the text, in pixels. <em>Write-only.</em>
* @property {number} lineHeight=18 - The height of a line of text, in pixels. <em>Write-only.</em>
* @property {Color} color=255,255,255 - The color of the text. Synonym: <code>textColor</code>. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>. <em>Write-only.</em>
* @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. <em>Write-only.</em>
* @property {number} backgroundAlpha=0.7 - The opacity of the background rectangle. <em>Write-only.</em>
* @property {number} backgroundAlpha=0.7 - The opacity of the background rectangle, <code>0.0</code> &ndash; <code>1.0</code>.
* <em>Write-only.</em>
*/
/**jsdoc
* The <code>"Rectangle"</code> {@link Overlays.OverlayType|OverlayType} is for 2D rectangles.
* The <code>"rectangle"</code> {@link Overlays.OverlayType|OverlayType} is for 2D rectangles.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* @typedef {object} Overlays.OverlayProperties-Rectangle
* @property {Rect} bounds - The position and size of the rectangle, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value = <code>bounds.x</code>. <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value = <code>bounds.y</code>. <em>Write-only.</em>
* @property {number} width - Integer width of the rectangle = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the rectangle = <code>bounds.height</code>. <em>Write-only.</em>
*
* @property {number} radius=0 - Integer corner radius, in pixels. <em>Write-only.</em>
* @property {Color} color=0,0,0 - The color of the overlay. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>. <em>Write-only.</em>
* @property {number} borderWidth=1 - Integer width of the border, in pixels. The border is drawn within the rectangle's bounds.
* It is not drawn unless either <code>borderColor</code> or <code>borderAlpha</code> are specified. <em>Write-only.</em>
* @property {number} radius=0 - Integer corner radius, in pixels. <em>Write-only.</em>
* @property {Color} borderColor=0,0,0 - The color of the border. <em>Write-only.</em>
* @property {number} borderAlpha=1.0 - The opacity of the border, <code>0.0</code> - <code>1.0</code>.
* @property {number} borderAlpha=1.0 - The opacity of the border, <code>0.0</code> &ndash; <code>1.0</code>.
* <em>Write-only.</em>
*/
/**jsdoc
* The <code>"Cube"</code> {@link Overlays.OverlayType|OverlayType} is for 3D cubes.
* The <code>"cube"</code> {@link Overlays.OverlayType|OverlayType} is for 3D cubes.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Box|Box} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Cube
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1475,24 +1518,33 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* @property {boolean} isSolid=false - <code>true</code> if the overlay is rendered as a solid, <code>false</code> if it is
* rendered as a wire frame.
* Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*/
/**jsdoc
* The <code>"Sphere"</code> {@link Overlays.OverlayType|OverlayType} is for 3D spheres.
* The <code>"sphere"</code> {@link Overlays.OverlayType|OverlayType} is for 3D spheres.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Sphere|Sphere} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Sphere
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1514,24 +1566,34 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* @property {boolean} isSolid=false - <code>true</code> if the overlay is rendered as a solid, <code>false</code> if it is
* rendered as a wire frame.
* Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*/
/**jsdoc
* The <code>"Rectangle3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D rectangles.
* The <code>"rectangle3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D rectangles.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Shape|Shape} entity, with the <code>shape</code>
* property value being <code>"Quad"</code>.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Rectangle3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1553,20 +1615,27 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* @property {boolean} isSolid=false - <code>true</code> if the overlay is rendered as a solid, <code>false</code> if it is
* rendered as a wire frame.
* Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*/
/**jsdoc
* <p>A <code>shape</code> {@link Overlays.OverlayType|OverlayType} may display as one of the following geometrical shapes:</p>
* <p>A <code>"shape"</code> {@link Overlays.OverlayType|OverlayType} may display as one of the following geometrical
* shapes:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Dimensions</th><th>Description</th></tr>
@ -1579,7 +1648,6 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <tr><td><code>"Dodecahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Hexagon"</code></td><td>3D</td><td>A hexagonal prism.</td></tr>
* <tr><td><code>"Icosahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Line"</code></td><td>1D</td><td>A line oriented in 3D.</td></tr>
* <tr><td><code>"Octagon"</code></td><td>3D</td><td>An octagonal prism.</td></tr>
* <tr><td><code>"Octahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Quad"</code></td><td>2D</td><td>A square oriented in 3D.</tr>
@ -1593,11 +1661,14 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
*/
/**jsdoc
* The <code>"Shape"</code> {@link Overlays.OverlayType|OverlayType} is for 3D shapes.
* The <code>"shape"</code> {@link Overlays.OverlayType|OverlayType} is for 3D shapes.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Shape|Shape} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Shape
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1619,21 +1690,31 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* @property {boolean} isSolid=false - <code>true</code> if the overlay is rendered as a solid, <code>false</code> if it is
* rendered as a wire frame.
* Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*
* @property {Overlays.Shape} shape=Hexagon - The geometrical shape of the overlay.
*/
/**jsdoc
* The <code>"Model"</code> {@link Overlays.OverlayType|OverlayType} is for 3D models.
* The <code>"model"</code> {@link Overlays.OverlayType|OverlayType} is for 3D models.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Model|Model} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Model
* @property {string} name - The name of the overlay.
*
@ -1646,42 +1727,39 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*
* @property {string} url - The URL of the FBX or OBJ model used for the overlay.
* @property {number} loadPriority=0.0 - The priority for loading and displaying the overlay. Overlays with higher values load
* first. <CURRENTLY NOT USED>
* @property {object.<name, url>} textures - Maps the named textures in the model to the JPG or PNG images in the urls.
* @property {string[]} jointNames - The names of the joints - if any - in the model. <em>Read-only.</em>
* @property {Quat[]} jointRotations - The relative rotations of the model's joints.
* @property {Vec3[]} jointTranslations - The relative translations of the model's joints.
* @property {Quat[]} jointOrientations - The absolute orientations of the model's joints, in world coordinates. <em>Read-only.</em>
* @property {Vec3[]} jointPositions - The absolute positions of the model's joints, in world coordinates. <em>Read-only.</em>
* @property {string} animationSettings.url="" - The URL of an FBX file containing an animation to play.
* @property {number} animationSettings.fps=0 - The frame rate (frames/sec) to play the animation at.
* @property {number} animationSettings.firstFrame=0 - The frame to start playing at.
* @property {number} animationSettings.lastFrame=0 - The frame to finish playing at.
* @property {number} animationSettings.currentFrame=0 - The current frame being played.
* @property {boolean} animationSettings.running=false - Whether or not the animation is playing.
* @property {boolean} animationSettings.loop=false - Whether or not the animation should repeat in a loop.
* @property {boolean} animationSettings.hold=false - Whether or not when the animation finishes, the rotations and
* translations of the last frame played should be maintained.
* @property {boolean} animationSettings.allowTranslation=false - Whether or not translations contained in the animation should
* be played.
* first. <em>Currently not used.</em>
* @property {Object.<string, string>|string} textures - Texture name, URL pairs used when rendering the model in place of the
* model's original textures, per the {@link Entities.EntityProperties-Model} property of the same name.
* <p>The value can be an object or a JSON string when setting the value; it is a JSON string when getting the value.</p>
* @property {Entities.AnimationProperties} animationSettings - An animation to play on the model.
*/
/**jsdoc
* The <code>"Text3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D text.
* The <code>"text3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D text.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Text|Text} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Text3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {Color} color=255,255,255 - The color of the overlay text. Synonym: <code>textColor</code>.
* @property {number} alpha=0.7 - The opacity of the overlay text, <code>0.0</code> &ndash; <code>1.0</code>.
* <p><em>Currently not used; use <code>textAlpha</code> instead.</em></p>
* <CURRENTLY BROKEN>
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1703,33 +1781,29 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
* @property {string} text="" - The text to display.Text does not automatically wrap; use <code>\n</code> for a line break.
* @property {number} textAlpha=1 - The text alpha value.
* @property {Color} backgroundColor=0,0,0 - The background color.
* @property {number} backgroundAlpha=0.7 - The background alpha value.
* @property {number} lineHeight=1 - The height of a line of text in meters.
* @property {number} leftMargin=0.1 - The left margin, in meters.
* @property {number} topMargin=0.1 - The top margin, in meters.
* @property {number} rightMargin=0.1 - The right margin, in meters.
* @property {number} bottomMargin=0.1 - The bottom margin, in meters.
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*/
/**jsdoc
* The <code>"Image3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D images.
* The <code>"image3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D images.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Image|Image} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Image3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1751,29 +1825,31 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
* @property {string} url - The URL of the PNG or JPG image to display.
* @property {Rect} subImage - The portion of the image to display. Defaults to the full image.
* @property {boolean} emissive - If <code>true</code>, the overlay is displayed at full brightness, otherwise it is rendered
* with scene lighting.
* @property {bool} keepAspectRatio=true - overlays will maintain the aspect ratio when the subImage is applied.
* @property {string} url - The URL of the image to display.
*/
/**jsdoc
* The <code>"Web"</code> {@link Overlays.OverlayType|OverlayType} is for 3D web surfaces.
* @typedef {object} Overlays.OverlayProperties-Web
* The <code>"web3d"</code> {@link Overlays.OverlayType|OverlayType} is for 3D web surfaces.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Web|Web} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Web3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1795,29 +1871,31 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
* @property {string} url - The URL of the Web page to display.
* @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page.
* @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay.
* @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second.
* @property {string} inputMode=Touch - The user input mode to use - either <code>"Touch"</code> or <code>"Mouse"</code>.
* @property {string} url - The URL of the web page to display.
*/
/**jsdoc
* The <code>"Line"</code> {@link Overlays.OverlayType|OverlayType} is for 3D lines.
* @typedef {object} Overlays.OverlayProperties-Line
* The <code>"line3d"</code> {@link Overlays.OverlayType|OverlayType} is for 3D lines.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-PolyLine|PolyLine} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Line3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
@ -1827,35 +1905,61 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*
* @property {Uuid} endParentID=null - The avatar, entity, or overlay that the end point of the line is parented to.
* <p><em>Currently doesn't work.</em></p>
* <CURRENTLY BROKEN>
* @property {number} endParentJointIndex=65535 - Integer value specifying the skeleton joint that the end point of the line is
* attached to if <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint". <CURRENTLY BROKEN>
* attached to if <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* <p><em>Currently doesn't work.</em></p>
* <CURRENTLY BROKEN>
* @property {Vec3} start - The start point of the line. Synonyms: <code>startPoint</code> and <code>p1</code>.
* <p><em>If <code>parentID<code> is set, use <code>localStart</code> to set the local position of the start point.</em></p>
* <CURRENTLY BROKEN>
* @property {Vec3} end - The end point of the line. Synonyms: <code>endPoint</code> and <code>p2</code>.
* <p><em>If <code>parentID<code> is set, use <code>localEnd</code> to set the local position of the end point.</em></p>
* <CURRENTLY BROKEN>
* @property {Vec3} localStart - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>start</code>. Synonym: <code>localPosition</code>.
* <code>parentID</code> set, otherwise the same value as <code>start</code>.
* <CURRENTLY BROKEN>
* @property {Vec3} localEnd - The local position of the overlay relative to its parent if the overlay has a
* <code>endParentID</code> set, otherwise the same value as <code>end</code>. <CURRENTLY BROKEN>
* <code>endParentID</code> set, otherwise the same value as <code>end</code>.
* <CURRENTLY BROKEN>
* @property {number} length - The length of the line, in meters. This can be set after creating a line with start and end
* points. <CURRENTLY BROKEN>
* points.
* <p><em>Currently doesn't work.</em></p>
* <CURRENTLY BROKEN>
* @property {number} glow=0 - If <code>glow > 0</code>, the line is rendered with a glow.
* @property {number} lineWidth=0.02 - Width of the line, in meters.
* <p><em>You can set this property's value but currently cannot retrieve its value. Use the <code>strokeWidths</code>
* property to retrieve its value instead.</p>
*/
/**jsdoc
* The <code>"Grid"</code> {@link Overlays.OverlayType|OverlayType} is for 3D grid.
* The <code>"grid"</code> {@link Overlays.OverlayType|OverlayType} is for 3D grids.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Grid|Grid} entity.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Grid
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1877,25 +1981,28 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} followCamera=true - If <code>true</code>, the grid is always visible even as the camera moves to another position.
* @property {number} majorGridEvery=5 - Integer number of <code>minorGridEvery</code> intervals at which to draw a thick grid line. Minimum value = <code>1</code>.
* @property {number} minorGridEvery=1 - Real number of meters at which to draw thin grid lines. Minimum value = <code>0.001</code>.
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*/
/**jsdoc
* The <code>"Circle"</code> {@link Overlays.OverlayType|OverlayType} is for 3D circle.
* @typedef {object} Overlays.OverlayProperties-Circle
* The <code>"circle3d"</code> {@link Overlays.OverlayType|OverlayType} is for 3D circles.
* It has properties in addition to the common {@link Overlays.OverlayProperties|OverlayProperties}.
* It additionally has properties per the {@link Entities.EntityProperties-Gizmo|Gizmo} entity, with the
* <code>gizmoType</code> property value being <code>"ring"</code>.
* <p class="important">Deprecated: Use local {@link Entities} instead.</p>
* @typedef {object} Overlays.OverlayProperties-Circle3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
@ -1912,62 +2019,75 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* <em>Read-only.</em>
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* @property {boolean} isSolid=false - <code>true</code> if the overlay is rendered as a solid, <code>false</code> if it is
* rendered as a wire frame.
* Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} ignorePickIntersection=false - <code>true</code> if {@link Picks} ignore the overlay, <code>false</code>
* if they don't.
* Synonym: <code>ignoreRayIntersection</code>.
* @property {boolean} drawInFront=false - <code>true</code> if the overlay is rendered on top of the world layer but behind
* the HUD surface.
* @property {boolean} drawHUDLayer=false - <code>true</code> if the overlay is rendered in front of everything, including the
* HUD surface.
* @property {boolean} grabbable=false - <code>true</code> if the overlay can be grabbed, <code>false</code> if it can't be.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {number} parentJointIndex=65535 - Integer value specifying the joint of the entity or avatar that the entity is
* parented to if <code>parentID</code> is set. Use 65535 or -1 to parent to the parent's position and orientation rather
* than a joint.
*
* @property {number} startAt = 0 - The counter - clockwise angle from the overlay's x-axis that drawing starts at in degrees.
* @property {number} endAt = 360 - The counter - clockwise angle from the overlay's x-axis that drawing ends at in degrees.
* @property {number} outerRadius = 1 - The outer radius of the overlay in meters. Synonym: <code>radius</code>.
* @property {number} innerRadius = 0 - The inner radius of the overlay in meters.
* @property {Color} color = 255, 255, 255 - The color of the overlay. Setting this value also sets the values of
* <code>innerStartColor</code>, <code>innerEndColor</code>, <code>outerStartColor</code>, and <code>outerEndColor</code>.
* @property {number} startAt=0 - The counter-clockwise angle from the overlay's x-axis that drawing starts at, in degrees.
* @property {number} endAt=360 - The counter-clockwise angle from the overlay's x-axis that drawing ends at, in degrees.
* @property {number} outerRadius=1 - The outer radius of the overlay in meters. Synonym: <code>radius</code>.
* @property {number} innerRadius=0 - The inner radius of the overlay in meters.
* @property {Color} color - Sets the color of the overlay. Setting this value sets the values of <code>innerStartColor</code>,
* <code>innerEndColor</code>, <code>outerStartColor</code>, and <code>outerEndColor</code>.
* <em>Write-only.</em>
* @property {Color} startColor - Sets the values of <code>innerStartColor</code> and <code>outerStartColor</code>.
* <em>Write - only.</em>
* <em>Write-only.</em>
* @property {Color} endColor - Sets the values of <code>innerEndColor</code> and <code>outerEndColor</code>.
* <em>Write - only.</em>
* <em>Write-only.</em>
* @property {Color} innerColor - Sets the values of <code>innerStartColor</code> and <code>innerEndColor</code>.
* <em>Write - only.</em>
* <em>Write-only.</em>
* @property {Color} outerColor - Sets the values of <code>outerStartColor</code> and <code>outerEndColor</code>.
* <em>Write - only.</em>
* @property {Color} innerStartcolor - The color at the inner start point of the overlay.
* @property {Color} innerEndColor - The color at the inner end point of the overlay.
* @property {Color} outerStartColor - The color at the outer start point of the overlay.
* @property {Color} outerEndColor - The color at the outer end point of the overlay.
* @property {number} alpha = 0.5 - The opacity of the overlay, <code>0.0</code> -<code>1.0</code>. Setting this value also sets
* the values of <code>innerStartAlpha</code>, <code>innerEndAlpha</code>, <code>outerStartAlpha</code>, and
* <code>outerEndAlpha</code>. Synonym: <code>Alpha</code>; <em>write - only</em>.
* <em>Write-only.</em>
* @property {Color} innerStartcolor=255,255,255 - The color at the inner start point of the overlay.
* @property {Color} innerEndColor=255,255,255 - The color at the inner end point of the overlay.
* @property {Color} outerStartColor=255,255,255 - The color at the outer start point of the overlay.
* @property {Color} outerEndColor=255,255,255 - The color at the outer end point of the overlay.
* @property {number} alpha - Sets the opacity of the overlay, <code>0.0</code> &ndash; <code>1.0</code>. Setting this value
* sets the values of <code>innerStartAlpha</code>, <code>innerEndAlpha</code>, <code>outerStartAlpha</code>, and
* <code>outerEndAlpha</code>. Synonym: <code>Alpha</code>.
* @property {number} startAlpha - Sets the values of <code>innerStartAlpha</code> and <code>outerStartAlpha</code>.
* <em>Write - only.</em>
* <em>Write-only.</em>
* @property {number} endAlpha - Sets the values of <code>innerEndAlpha</code> and <code>outerEndAlpha</code>.
* <em>Write - only.</em>
* <em>Write-only.</em>
* @property {number} innerAlpha - Sets the values of <code>innerStartAlpha</code> and <code>innerEndAlpha</code>.
* <em>Write - only.</em>
* <em>Write-only.</em>
* @property {number} outerAlpha - Sets the values of <code>outerStartAlpha</code> and <code>outerEndAlpha</code>.
* <em>Write - only.</em>
* @property {number} innerStartAlpha = 0 - The alpha at the inner start point of the overlay.
* @property {number} innerEndAlpha = 0 - The alpha at the inner end point of the overlay.
* @property {number} outerStartAlpha = 0 - The alpha at the outer start point of the overlay.
* @property {number} outerEndAlpha = 0 - The alpha at the outer end point of the overlay.
* <em>Write-only.</em>
* @property {number} innerStartAlpha=0.7 - The opacity at the inner start point of the overlay, <code>0.0</code> &ndash;
* <code>1.0</code>.
* @property {number} innerEndAlpha=0.7 - The opacity at the inner end point of the overlay, <code>0.0</code> &ndash;
* <code>1.0</code>.
* @property {number} outerStartAlpha=0.7 - The opacity at the outer start point of the overlay, <code>0.0</code> &ndash;
* <code>1.0</code>.
* @property {number} outerEndAlpha=0.7 - The opacity at the outer end point of the overlay, <code>0.0</code> &ndash;
* <code>1.0</code>.
*
* @property {boolean} hasTickMarks = false - If <code>true</code>, tick marks are drawn.
* @property {number} majorTickMarksAngle = 0 - The angle between major tick marks, in degrees.
* @property {number} minorTickMarksAngle = 0 - The angle between minor tick marks, in degrees.
* @property {number} majorTickMarksLength = 0 - The length of the major tick marks, in meters. A positive value draws tick marks
* @property {boolean} hasTickMarks=false - <code>true</code> if tick marks are drawn, <code>false</code> if they aren't.
* @property {number} majorTickMarksAngle=0 - The angle between major tick marks, in degrees.
* @property {number} minorTickMarksAngle=0 - The angle between minor tick marks, in degrees.
* @property {number} majorTickMarksLength=0 - The length of the major tick marks, in meters. A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {number} minorTickMarksLength = 0 - The length of the minor tick marks, in meters. A positive value draws tick marks
* @property {number} minorTickMarksLength=0 - The length of the minor tick marks, in meters. A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {Color} majorTickMarksColor = 0, 0, 0 - The color of the major tick marks.
* @property {Color} minorTickMarksColor = 0, 0, 0 - The color of the minor tick marks.
* @property {Color} majorTickMarksColor=0,0,0 - The color of the major tick marks.
* @property {Color} minorTickMarksColor=0,0,0 - The color of the minor tick marks.
*/

View file

@ -68,17 +68,23 @@ public:
};
/**jsdoc
* (Note: 3D Overlays are deprecated. Use local entities instead.) The Overlays API provides facilities to create and interact with overlays. Overlays are 2D and 3D objects visible only to
* yourself and that aren't persisted to the domain. They are used for UI.
* The <code>Overlays</code> API provides facilities to create and interact with overlays. These are 2D and 3D objects visible
* only to yourself and that aren't persisted to the domain. They are used for UI.
*
* <p><strong>Note:</strong> 3D overlays are local {@link Entities}, internally, so many of the methods also work with
* entities.</p>
*
* <p class="important">3D overlays are deprecated: Use local {@link Entities} for these instead.</p>
*
* @namespace Overlays
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Uuid} keyboardFocusOverlay - Get or set the {@link Entities.EntityTypes|Web} entity that has keyboard focus.
* If no entity has keyboard focus, returns <code>null</code>; set to <code>null</code> or {@link Uuid(0)|Uuid.NULL} to
* clear keyboard focus.
* @property {Uuid} keyboardFocusOverlay - The <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
* ({@link Entities.EntityProperties-Web|Web} entity) that has keyboard focus. If no overlay (entity) has keyboard focus,
* returns <code>null</code>; set to <code>null</code> or {@link Uuid(0)|Uuid.NULL} to clear keyboard focus.
*/
class Overlays : public QObject {
@ -118,7 +124,7 @@ public:
public slots:
/**jsdoc
* Add an overlay to the scene.
* Adds an overlay to the scene.
* @function Overlays.addOverlay
* @param {Overlays.OverlayType} type - The type of the overlay to add.
* @param {Overlays.OverlayProperties} properties - The properties of the overlay to add.
@ -134,19 +140,21 @@ public slots:
QUuid addOverlay(const QString& type, const QVariant& properties);
/**jsdoc
* Create a clone of an existing entity (or 2D overlay).
* Creates a clone of an existing overlay (or entity).
* <p>Note: For cloning behavior of 3D overlays and entities, see {@link Entities.cloneEntity}.</p>
* @function Overlays.cloneOverlay
* @param {Uuid} id - The ID of the entity/2D overlay to clone.
* @returns {Uuid} The ID of the new object if successful, otherwise {@link Uuid(0)|Uuid.NULL}.
* @param {Uuid} id - The ID of the overlay (or entity) to clone.
* @returns {Uuid} The ID of the new overlay (or entity) if successful, otherwise {@link Uuid(0)|Uuid.NULL}.
*/
QUuid cloneOverlay(const QUuid& id);
/**jsdoc
* Edit an overlay's properties.
* Edits an overlay's (or entity's) properties.
* @function Overlays.editOverlay
* @param {Uuid} id - The ID of the overlay to edit.
* @param {Uuid} id - The ID of the overlay (or entity) to edit.
* @param {Overlays.OverlayProperties} properties - The properties changes to make.
* @returns {boolean} <code>true</code> if the overlay was found and edited, otherwise <code>false</code>.
* @returns {boolean} <code>false</code> if Interface is exiting. Otherwise, if a 2D overlay then <code>true</code> always,
* and if a 3D overlay then <code>true</code> if the overlay was found and edited, otherwise <code>false</code>.
* @example <caption>Add an overlay in front of your avatar then change its color.</caption>
* var overlay = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
@ -163,12 +171,11 @@ public slots:
bool editOverlay(const QUuid& id, const QVariant& properties);
/**jsdoc
* Edit multiple overlays' properties.
* Edits the properties of multiple overlays (or entities).
* @function Overlays.editOverlays
* @param propertiesById {object.<Uuid, Overlays.OverlayProperties>} - An object with overlay IDs as keys and
* @param propertiesById {object.<Uuid, Overlays.OverlayProperties>} - An object with overlay (or entity) IDs as keys and
* {@link Overlays.OverlayProperties|OverlayProperties} edits to make as values.
* @returns {boolean} <code>true</code> if all overlays were found and edited, otherwise <code>false</code> (some may have
* been found and edited).
* @returns {boolean} <code>false</code> if Interface is exiting, otherwise <code>true</code>.
* @example <caption>Create two overlays in front of your avatar then change their colors.</caption>
* var overlayA = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: -0.3, y: 0, z: -3 })),
@ -192,18 +199,18 @@ public slots:
bool editOverlays(const QVariant& propertiesById);
/**jsdoc
* Delete an entity or 2D overlay.
* Deletes an overlay (or entity).
* @function Overlays.deleteOverlay
* @param {Uuid} id - The ID of the object to delete.
* @param {Uuid} id - The ID of the overlay (or entity) to delete.
*/
void deleteOverlay(const QUuid& id);
/**jsdoc
* Get the type of an entity or 2D overlay.
* Gets the type of an overlay.
* @function Overlays.getOverlayType
* @param {Uuid} id - The ID of the object to get the type of.
* @returns {string} The type of the object if found, otherwise an empty string.
* @example <caption>Create an object in front of your avatar then get and report its type.</caption>
* @param {Uuid} id - The ID of the overlay to get the type of.
* @returns {Overlays.OverlayType} The type of the overlay if found, otherwise <code>"unknown"</code>.
* @example <caption>Create an overlay in front of your avatar then get and report its type.</caption>
* var overlay = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
* rotation: MyAvatar.orientation,
@ -211,56 +218,82 @@ public slots:
* solid: true
* });
* var type = Overlays.getOverlayType(overlay);
* print("Type: " + type);
* print("Type: " + type); // cube
*/
QString getOverlayType(const QUuid& id);
/**jsdoc
* Get the overlay script object. In particular, this is useful for accessing the event bridge for a <code>web3d</code>
* overlay.
* Gets an overlay's (or entity's) script object. In particular, this is useful for accessing a
* <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay's <code>EventBridge</code> script object to
* exchange messages with the web page script.
* <p>To send a message from an Interface script to a <code>"web3d"</code> overlay over its event bridge:</p>
* <pre class="prettyprint"><code>var overlayObject = Overlays.getOverlayObject(overlayID);
* overlayObject.emitScriptEvent(message);</code></pre>
* <p>To receive a message from a <code>"web3d"</code> overlay over its event bridge in an Interface script:</p>
* <pre class="prettyprint"><code>var overlayObject = Overlays.getOverlayObject(overlayID);
* overlayObject.webEventReceived.connect(function(message) {
* ...
* };</code></pre>
* @function Overlays.getOverlayObject
* @param {Uuid} overlayID - The ID of the overlay to get the script object of.
* @returns {object} The script object for the overlay if found.
* @example <caption>Receive "hello" messages from a <code>web3d</code> overlay.</caption>
* // HTML file: name "web3d.html".
* @example <caption>Exchange messages with a <code>"web3d"</code> overlay.</caption>
* // HTML file, name: "web3d.html".
* <!DOCTYPE html>
* <html>
* <head>
* <title>HELLO</title>
* </head>
* <body>
* <h1>HELLO</h1></h1>
* <h1>HELLO</h1>
* <script>
* function onScriptEventReceived(message) {
* // Message received from the script.
* console.log("Message received: " + message);
* }
*
* EventBridge.scriptEventReceived.connect(onScriptEventReceived);
*
* setInterval(function () {
* // Send a message to the script.
* EventBridge.emitWebEvent("hello");
* }, 2000);
* </script>
* </body>
* </html>
*
* // Script file.
* var web3dOverlay = Overlays.addOverlay("web3d", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.5, z: -3 })),
* rotation: MyAvatar.orientation,
* url: Script.resolvePath("web3d.html"),
* alpha: 1.0
* });
*
* function onWebEventReceived(event) {
* print("onWebEventReceived() : " + JSON.stringify(event));
*
* // Interface script file.
* var web3DOverlay = Overlays.addOverlay("web3d", {
* type: "Web",
* position : Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y : 0.5, z : -3 })),
* rotation : MyAvatar.orientation,
* sourceUrl : Script.resolvePath("web3d.html"),
* alpha : 1.0
* });
*
* var overlayObject;
*
* function onWebEventReceived(message) {
* // Message received.
* print("Message received: " + message);
*
* // Send a message back.
* overlayObject.emitScriptEvent(message + " back");
* }
*
* overlayObject = Overlays.getOverlayObject(web3dOverlay);
* overlayObject.webEventReceived.connect(onWebEventReceived);
*
* Script.scriptEnding.connect(function () {
* Overlays.deleteOverlay(web3dOverlay);
*
* Script.setTimeout(function() {
* overlayObject = Overlays.getOverlayObject(web3DOverlay);
* overlayObject.webEventReceived.connect(onWebEventReceived);
* }, 500);
*
* Script.scriptEnding.connect(function() {
* Overlays.deleteOverlay(web3DOverlay);
* });
*/
QObject* getOverlayObject(const QUuid& id);
/**jsdoc
* Get the ID of the 2D overlay at a particular point on the screen or HUD.
* Gets the ID of the 2D overlay at a particular point on the desktop screen or HUD surface.
* @function Overlays.getOverlayAtPoint
* @param {Vec2} point - The point to check for an overlay.
* @returns {Uuid} The ID of the 2D overlay at the specified point if found, otherwise <code>null</code>.
@ -279,10 +312,11 @@ public slots:
QUuid getOverlayAtPoint(const glm::vec2& point);
/**jsdoc
* Get the value of a 3D overlay's property.
* Gets a specified property value of a 3D overlay (or entity).
* <p><strong>Note:</strong> 2D overlays' property values cannot be retrieved.</p>
* @function Overlays.getProperty
* @param {Uuid} id - The ID of the overlay. <em>Must be for a 3D {@link Overlays.OverlayType|OverlayType}.</em>
* @param {string} property - The name of the property value to get.
* @param {Uuid} id - The ID of the 3D overlay (or entity).
* @param {string} property - The name of the property to get the value of.
* @returns {object} The value of the property if the 3D overlay and property can be found, otherwise
* <code>undefined</code>.
* @example <caption>Create an overlay in front of your avatar then report its alpha property value.</caption>
@ -298,12 +332,13 @@ public slots:
QVariant getProperty(const QUuid& id, const QString& property);
/**jsdoc
* Get the values of an overlay's properties.
* Gets specified property values of a 3D overlay (or entity).
* <p><strong>Note:</strong> 2D overlays' property values cannot be retrieved.</p>
* @function Overlays.getProperties
* @param {Uuid} id - The ID of the overlay.
* @param {Array.<string>} properties - An array of names of properties to get the values of.
* @returns {Overlays.OverlayProperties} The values of valid properties if the overlay can be found, otherwise
* <code>undefined</code>.
* @param {Uuid} id - The ID of the overlay (or entity).
* @param {Array.<string>} properties - The names of the properties to get the values of.
* @returns {Overlays.OverlayProperties} The values of valid properties if the overlay can be found, otherwise an empty
* object.
* @example <caption>Create an overlay in front of your avatar then report some of its properties.</caption>
* var overlay = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
@ -317,11 +352,11 @@ public slots:
QVariantMap getProperties(const QUuid& id, const QStringList& properties);
/**jsdoc
* Get the values of multiple overlays' properties.
* Gets the values of multiple overlays' (or entities') properties.
* @function Overlays.getOverlaysProperties
* @param propertiesById {object.<Uuid, Array.<string>>} - An object with overlay IDs as keys and arrays of the names of
* properties to get for each as values.
* @returns {object.<Uuid, Overlays.OverlayProperties>} An object with overlay IDs as keys and
* @param propertiesById {object.<Uuid, Array.<string>>} - An object with overlay (or entity) IDs as keys and arrays of the
* names of properties to get for each as values.
* @returns {object.<Uuid, Overlays.OverlayProperties>} An object with overlay (or entity) IDs as keys and
* {@link Overlays.OverlayProperties|OverlayProperties} as values.
* @example <caption>Create two cube overlays in front of your avatar then get some of their properties.</caption>
* var overlayA = Overlays.addOverlay("cube", {
@ -345,22 +380,20 @@ public slots:
QVariantMap getOverlaysProperties(const QVariant& overlaysProperties);
/**jsdoc
* Find the closest 3D overlay intersected by a {@link PickRay}. Overlays with their <code>drawInFront</code> property set
* to <code>true</code> have priority over overlays that don't, except that tablet overlays have priority over any
* <code>drawInFront</code> overlays behind them. I.e., if a <code>drawInFront</code> overlay is behind one that isn't
* <code>drawInFront</code>, the <code>drawInFront</code> overlay is returned, but if a tablet overlay is in front of a
* <code>drawInFront</code> overlay, the tablet overlay is returned.
* Finds the closest 3D overlay (or local entity) intersected by a {@link PickRay}.
* @function Overlays.findRayIntersection
* @param {PickRay} pickRay - The PickRay to use for finding overlays.
* @param {boolean} [precisionPicking=false] - <em>Unused</em>; exists to match Entity API.
* @param {Array.<Uuid>} [include=[]] - If not empty then the search is restricted to these overlays.
* @param {Array.<Uuid>} [discard=[]] - Overlays to ignore during the search.
* @param {boolean} [visibleOnly=false] - If <code>true</code> then only entities that are
* <code>{@link Entities.EntityProperties|visible}<code> are searched.
* @param {boolean} [collideableOnly=false] - If <code>true</code> then only entities that are not
* <code>{@link Entities.EntityProperties|collisionless}</code> are searched.
* @returns {Overlays.RayToOverlayIntersectionResult} The closest 3D overlay intersected by <code>pickRay</code>, taking
* into account <code>overlayIDsToInclude</code> and <code>overlayIDsToExclude</code> if they're not empty.
* @param {boolean} [precisionPicking=false] - <code>true</code> to pick against precise meshes, <code>false</code> to pick
* against coarse meshes. If <code>true</code> and the intersected entity is a model, the result's
* <code>extraInfo</code> property includes more information than it otherwise would.
* @param {Array.<Uuid>} [include=[]] - If not empty, then the search is restricted to these overlays (and local entities).
* @param {Array.<Uuid>} [discard=[]] - Overlays (and local entities) to ignore during the search.
* @param {boolean} [visibleOnly=false] - <code>true</code> if only overlays (and local entities) that are
* <code>{@link Overlays.OverlayProperties|visible}</code> should be searched.
* @param {boolean} [collideableOnly=false] - <code>true</code> if only local entities that are not
* <code>{@link Entities.EntityProperties|collisionless}</code> should be searched.
* @returns {Overlays.RayToOverlayIntersectionResult} The result of the search for the first intersected overlay (or local
* entity.
* @example <caption>Create a cube overlay in front of your avatar. Report 3D overlay intersection details for mouse
* clicks.</caption>
* var overlay = Overlays.addOverlay("cube", {
@ -384,12 +417,13 @@ public slots:
bool collidableOnly = false);
/**jsdoc
* Return a list of local entities with bounding boxes that touch a search sphere.
* Gets a list of visible 3D overlays (local entities) with bounding boxes that touch a search sphere.
* @function Overlays.findOverlays
* @param {Vec3} center - The center of the search sphere.
* @param {number} radius - The radius of the search sphere.
* @returns {Uuid[]} An array of entity IDs with bounding boxes that touch a search sphere.
* @example <caption>Create two cube entities in front of your avatar then search for entities near your avatar.</caption>
* @returns {Uuid[]} The IDs of the overlays (local entities) that are visible and have bounding boxes that touch a search
* sphere.
* @example <caption>Create two overlays in front of your avatar then search for overlays near your avatar.</caption>
* var overlayA = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: -0.3, y: 0, z: -3 })),
* rotation: MyAvatar.orientation,
@ -411,11 +445,13 @@ public slots:
QVector<QUuid> findOverlays(const glm::vec3& center, float radius);
/**jsdoc
* Check whether an overlay's assets have been loaded. For example, for an <code>image</code> overlay the result indicates
* whether its image has been loaded.
* Checks whether an overlay's (or entity's) assets have been loaded. For example, for an
* <code>{@link Overlays.OverlayProperties-Image|"image"}</code> overlay, the result indicates whether its image has been
* loaded.
* @function Overlays.isLoaded
* @param {Uuid} id - The ID of the overlay to check.
* @returns {boolean} <code>true</code> if the overlay's assets have been loaded, otherwise <code>false</code>.
* @param {Uuid} id - The ID of the overlay (or entity) to check.
* @returns {boolean} <code>true</code> if the overlay's (or entity's) assets have been loaded, otherwise
* <code>false</code>.
* @example <caption>Create an image overlay and report whether its image is loaded after 1s.</caption>
* var overlay = Overlays.addOverlay("image", {
* bounds: { x: 100, y: 100, width: 200, height: 200 },
@ -429,55 +465,60 @@ public slots:
bool isLoaded(const QUuid& id);
/**jsdoc
* Calculates the size of the given text in the specified object if it is a text entity or overlay.
* Calculates the size of some text in a text overlay (or entity). The overlay (or entity) need not be set visible.
* <p><strong>Note:</strong> The size of text in a 3D overlay (or entity) cannot be calculated immediately after the
* overlay (or entity) is created; a short delay is required while the overlay (or entity) finishes being created.</p>
* @function Overlays.textSize
* @param {Uuid} id - The ID of the object to use for calculation.
* @param {Uuid} id - The ID of the overlay (or entity) to use for calculation.
* @param {string} text - The string to calculate the size of.
* @returns {Size} The size of the <code>text</code> if the object is a text entity or overlay, otherwise
* <code>{ height: 0, width : 0 }</code>. If the object is a 2D overlay, the size is in pixels; if the object is an entity,
* the size is in meters.
* @returns {Size} The size of the <code>text</code> if the object is a text overlay (or entity), otherwise
* <code>{ height: 0, width : 0 }</code>. If the object is a 2D overlay, the size is in pixels; if the object is a 3D
* overlay (or entity), the size is in meters.
* @example <caption>Calculate the size of "hello" in a 3D text entity.</caption>
* var overlay = Overlays.addOverlay("text3d", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })),
* rotation: MyAvatar.orientation,
* text: "hello",
* lineHeight: 0.2
* lineHeight: 0.2,
* visible: false
* });
* var textSize = Overlays.textSize(overlay, "hello");
* print("Size of \"hello\": " + JSON.stringify(textSize));
*
* Script.setTimeout(function() {
* var textSize = Overlays.textSize(overlay, "hello");
* print("Size of \"hello\": " + JSON.stringify(textSize));
* }, 500);
*/
QSizeF textSize(const QUuid& id, const QString& text);
/**jsdoc
* Get the width of the window or HUD.
* Gets the width of the Interface window or HUD surface.
* @function Overlays.width
* @returns {number} The width, in pixels, of the Interface window if in desktop mode or the HUD if in HMD mode.
* @returns {number} The width, in pixels, of the Interface window if in desktop mode or the HUD surface if in HMD mode.
*/
float width();
/**jsdoc
* Get the height of the window or HUD.
* Gets the height of the Interface window or HUD surface.
* @function Overlays.height
* @returns {number} The height, in pixels, of the Interface window if in desktop mode or the HUD if in HMD mode.
* @returns {number} The height, in pixels, of the Interface window if in desktop mode or the HUD surface if in HMD mode.
*/
float height();
/**jsdoc
* Check if there is an object of a given ID.
* Checks if an overlay (or entity) exists.
* @function Overlays.isAddedOverlay
* @param {Uuid} id - The ID to check.
* @returns {boolean} <code>true</code> if an object with the given ID exists, <code>false</code> otherwise.
* @param {Uuid} id - The ID of the overlay (or entity) to check.
* @returns {boolean} <code>true</code> if an overlay (or entity) with the given ID exists, <code>false</code> if it doesn't.
*/
bool isAddedOverlay(const QUuid& id);
/**jsdoc
* Generate a mouse press event on an overlay.
* Generates a mouse press event on an overlay (or local entity).
* @function Overlays.sendMousePressOnOverlay
* @param {Uuid} id - The ID of the overlay to generate a mouse press event on.
* @param {Uuid} id - The ID of the overlay (or local entity) to generate a mouse press event on.
* @param {PointerEvent} event - The mouse press event details.
* @example <caption>Create a 2D rectangle overlay plus a 3D cube overlay and generate mousePressOnOverlay events for the 2D
* overlay.</caption>
* var overlay = Overlays.addOverlay("cube", {
* @example <caption>Create a 2D rectangle overlay plus a 3D cube overlay and generate mousePressOnOverlay events for the
* 2D overlay.</caption>
* var overlay3D = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 0.3, y: 0.3, z: 0.3 },
@ -485,7 +526,7 @@ public slots:
* });
* print("3D overlay: " + overlay);
*
* var overlay = Overlays.addOverlay("rectangle", {
* var overlay2D = Overlays.addOverlay("rectangle", {
* bounds: { x: 100, y: 100, width: 200, height: 100 },
* color: { red: 255, green: 255, blue: 255 }
* });
@ -511,66 +552,69 @@ public slots:
void sendMousePressOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a mouse release event on an overlay.
* Generates a mouse release event on an overlay (or local entity).
* @function Overlays.sendMouseReleaseOnOverlay
* @param {Uuid} id - The ID of the overlay to generate a mouse release event on.
* @param {Uuid} id - The ID of the overlay (or local entity) to generate a mouse release event on.
* @param {PointerEvent} event - The mouse release event details.
*/
void sendMouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a mouse move event on an overlay.
* Generates a mouse move event on an overlay (or local entity).
* @function Overlays.sendMouseMoveOnOverlay
* @param {Uuid} id - The ID of the overlay to generate a mouse move event on.
* @param {Uuid} id - The ID of the overlay (or local entity) to generate a mouse move event on.
* @param {PointerEvent} event - The mouse move event details.
*/
void sendMouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a hover enter event on an overlay.
* Generates a hover enter event on an overlay (or local entity).
* @function Overlays.sendHoverEnterOverlay
* @param {Uuid} id - The ID of the overlay to generate a hover enter event on.
* @param {Uuid} id - The ID of the overlay (or local entity) to generate a hover enter event on.
* @param {PointerEvent} event - The hover enter event details.
*/
void sendHoverEnterOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a hover over event on an overlay.
* Generates a hover over event on an overlay (or entity).
* @function Overlays.sendHoverOverOverlay
* @param {Uuid} id - The ID of the overlay to generate a hover over event on.
* @param {Uuid} id - The ID of the overlay (or local entity) to generate a hover over event on.
* @param {PointerEvent} event - The hover over event details.
*/
void sendHoverOverOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a hover leave event on an overlay.
* Generates a hover leave event on an overlay (or local entity).
* @function Overlays.sendHoverLeaveOverlay
* @param {Uuid} id - The ID of the overlay to generate a hover leave event on.
* @param {Uuid} id - The ID of the overlay (or local entity) to generate a hover leave event on.
* @param {PointerEvent} event - The hover leave event details.
*/
void sendHoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Get the ID of the Web3D entity that has keyboard focus.
* Gets the ID of the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
* ({@link Entities.EntityProperties-Web|Web} entity) that has keyboard focus.
* @function Overlays.getKeyboardFocusOverlay
* @returns {Uuid} The ID of the {@link Entities.EntityTypes|Web} overlay that has focus, if any, otherwise
* <code>null</code>.
* @returns {Uuid} The ID of the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
* ({@link Entities.EntityProperties-Web|Web} entity) that has focus, if any, otherwise <code>null</code>.
*/
QUuid getKeyboardFocusOverlay() { return DependencyManager::get<EntityScriptingInterface>()->getKeyboardFocusEntity(); }
/**jsdoc
* Set the Web3D entity that has keyboard focus.
* Sets the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
* ({@link Entities.EntityProperties-Web|Web} entity) that has keyboard focus.
* @function Overlays.setKeyboardFocusOverlay
* @param {Uuid} id - The ID of the {@link Entities.EntityTypes|Web} entity to set keyboard focus to. Use
* <code>null</code> or {@link Uuid(0)|Uuid.NULL} to unset keyboard focus from an overlay.
* @param {Uuid} id - The ID of the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
* ({@link Entities.EntityProperties-Web|Web} entity) to set keyboard focus to. Use <code>null</code> or
* {@link Uuid(0)|Uuid.NULL} to unset keyboard focus from an overlay (entity).
*/
void setKeyboardFocusOverlay(const QUuid& id) { DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusEntity(id); }
signals:
/**jsdoc
* Triggered when an overlay is deleted.
* Triggered when an overlay (or entity) is deleted.
* @function Overlays.overlayDeleted
* @param {Uuid} id - The ID of the overlay that was deleted.
* @param {Uuid} id - The ID of the overlay (or entity) that was deleted.
* @returns {Signal}
* @example <caption>Create an overlay then delete it after 1s.</caption>
* var overlay = Overlays.addOverlay("cube", {

View file

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.0)
set(ENV{MACOSX_DEPLOYMENT_TARGET} 10.9)
project(HQLauncher)
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
include("cmake/macros/SetPackagingParameters.cmake")
set(src_files
src/Launcher.h
src/Launcher.m
@ -59,15 +60,17 @@ set_target_properties(${this_target} PROPERTIES
set(MACOSX_BUNDLE_ICON_FILE "interface.icns")
function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
if (NOT DEFINED ${_RESULT_NAME})
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
else()
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
endif()
if (NOT DEFINED ${_RESULT_NAME})
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
else()
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
endif()
endif()
endfunction()
set_packaging_parameters()
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME}
MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME})
@ -77,6 +80,7 @@ if ("${LAUNCHER_HMAC_SECRET}" STREQUAL "")
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE LAUNCHER_HMAC_SECRET="${LAUNCHER_HMAC_SECRET}")
target_compile_definitions(${PROJECT_NAME} PRIVATE LAUNCHER_BUILD_VERSION="${BUILD_VERSION}")
file(GLOB NIB_FILES "nib/*.xib")

View file

@ -0,0 +1,45 @@
#
# SetPackagingParameters.cmake
# cmake/macros
#
# Created by Leonardo Murillo on 07/14/2015.
# Copyright 2015 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
# This macro checks some Jenkins defined environment variables to determine the origin of this build
# and decides how targets should be packaged.
macro(SET_PACKAGING_PARAMETERS)
set(PR_BUILD 0)
set(PRODUCTION_BUILD 0)
set(DEV_BUILD 0)
set(BUILD_NUMBER 0)
set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV")
set_from_env(RELEASE_NUMBER RELEASE_NUMBER "")
set_from_env(STABLE_BUILD STABLE_BUILD 0)
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
set(BUILD_NUMBER ${RELEASE_NUMBER})
if (RELEASE_TYPE STREQUAL "PRODUCTION")
set(PRODUCTION_BUILD 1)
set(BUILD_VERSION ${RELEASE_NUMBER})
# add definition for this release type
add_definitions(-DPRODUCTION_BUILD)
elseif (RELEASE_TYPE STREQUAL "PR")
set(PR_BUILD 1)
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
# add definition for this release type
add_definitions(-DPR_BUILD)
else ()
set(DEV_BUILD 1)
set(BUILD_VERSION "dev")
endif ()
endmacro(SET_PACKAGING_PARAMETERS)

View file

@ -102,12 +102,22 @@
<action selector="termsOfService:" target="YVh-OH-vU8" id="bgc-08-8Lj"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oJs-u5-OOJ">
<rect key="frame" x="380" y="0.0" width="130" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Label" id="H6o-Xs-wK1">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="138.5" y="154"/>
</customView>
<customObject id="YVh-OH-vU8" customClass="DisplayNameScreen">
<connections>
<outlet property="backgroundImage" destination="aus-lo-eVi" id="SRc-pV-lXG"/>
<outlet property="buildVersion" destination="oJs-u5-OOJ" id="avj-j2-5P6"/>
<outlet property="displayName" destination="Vhg-rq-xUH" id="Fb5-im-2hx"/>
<outlet property="smallLogo" destination="j8K-TD-h7e" id="OVd-p3-nu6"/>
</connections>

View file

@ -69,12 +69,22 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="CBD-Vk-Xd4"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Omk-5j-C6r">
<rect key="frame" x="381" y="0.0" width="130" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Label" id="xpG-oP-agI">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="138.5" y="152"/>
</customView>
<customObject id="nWn-x7-LxT" customClass="ErrorViewController">
<connections>
<outlet property="backgroundImage" destination="eih-a8-Pqa" id="2xh-8r-1Qu"/>
<outlet property="buildVersion" destination="Omk-5j-C6r" id="aTp-c3-RVy"/>
<outlet property="smallLogo" destination="ugn-Hk-gWL" id="EVI-d3-mf5"/>
<outlet property="voxelImage" destination="jmW-5q-Mf3" id="NiI-cY-tAf"/>
</connections>

View file

@ -119,12 +119,22 @@
<action selector="havingTrouble:" target="NkF-nk-81S" id="tsf-tC-aqq"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EsT-hn-six">
<rect key="frame" x="380" y="0.0" width="130" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Label" id="AGt-jH-mX2">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="138.5" y="154"/>
</customView>
<customObject id="NkF-nk-81S" customClass="LoginScreen">
<connections>
<outlet property="backgroundImage" destination="L56-Jv-0N8" id="INT-rB-YtG"/>
<outlet property="buildVersion" destination="EsT-hn-six" id="Z4k-Gv-U5g"/>
<outlet property="button" destination="jKE-fV-Tjv" id="or6-tG-r6R"/>
<outlet property="header" destination="hIC-qf-Abj" id="sVQ-rl-cvR"/>
<outlet property="orginization" destination="L7W-3n-OKy" id="TiL-wn-Z2b"/>

View file

@ -53,6 +53,15 @@
<rect key="frame" x="68" y="78" width="394" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</progressIndicator>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="U3I-TA-xRz">
<rect key="frame" x="380" y="0.0" width="130" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Label" id="8YH-Td-daK">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="138.5" y="154"/>
</customView>
@ -60,6 +69,7 @@
<connections>
<outlet property="background" destination="kuY-e2-Hqb" id="CBc-bD-ux7"/>
<outlet property="boldStatus" destination="EMF-E4-qLL" id="udm-8B-7lt"/>
<outlet property="buildVersion" destination="U3I-TA-xRz" id="HDI-tW-1cC"/>
<outlet property="progressView" destination="aEr-fi-fkV" id="OUy-Qp-tiP"/>
<outlet property="smallLogo" destination="uh2-4K-n56" id="pYg-hP-nr5"/>
<outlet property="smallStatus" destination="BSg-lp-njL" id="ziz-ek-Lq4"/>

View file

@ -26,11 +26,21 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="qC6-tI-Uwf"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EgF-VK-Hfo">
<rect key="frame" x="380" y="0.0" width="130" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Label" id="gWS-UL-cjB">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="119.5" y="134"/>
</customView>
<customObject id="iJ0-FI-XIf" customClass="SplashScreen">
<connections>
<outlet property="buildVersion" destination="EgF-VK-Hfo" id="lVp-Ua-9Mt"/>
<outlet property="imageView" destination="qtD-mb-qqq" id="rCt-Gd-Uux"/>
<outlet property="logoImage" destination="2i5-Zw-nH7" id="7tM-sX-cvR"/>
</connections>

View file

@ -6,6 +6,7 @@
@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
@property (nonatomic, assign) IBOutlet NSTextField* displayName;
@property (nonatomic, assign) IBOutlet NSTextField* buildVersion;
@end
@implementation DisplayNameScreen
@ -13,10 +14,9 @@
[self.backgroundImage setImage: [NSImage imageNamed:hifiBackgroundFilename]];
[self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]];
NSMutableAttributedString* displayNameString = [[NSMutableAttributedString alloc] initWithString:@"Display Name"];
[self.buildVersion setStringValue: [@"V." stringByAppendingString:@LAUNCHER_BUILD_VERSION]];
[displayNameString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0, displayNameString.length)];
[displayNameString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,displayNameString.length)];
[self.displayName setPlaceholderAttributedString:displayNameString];
[self.displayName setTarget:self];
[self.displayName setAction:@selector(login:)];

View file

@ -6,6 +6,7 @@
@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
@property (nonatomic, assign) IBOutlet NSImageView* voxelImage;
@property (nonatomic, assign) IBOutlet NSTextField* buildVersion;
@end
@ -16,6 +17,7 @@
[self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]];
[self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]];
[self.voxelImage setImage:[NSImage imageNamed:hifiVoxelFilename]];
[self.buildVersion setStringValue: [@"V." stringByAppendingString:@LAUNCHER_BUILD_VERSION]];
}
-(IBAction)resartLauncher:(id)sender

View file

@ -12,6 +12,7 @@
@property (nonatomic, assign) IBOutlet NSTextField* smallHeader;
@property (nonatomic, assign) IBOutlet NSTextField* trouble;
@property (nonatomic, assign) IBOutlet NSButton* button;
@property (nonatomic, assign) IBOutlet NSTextField* buildVersion;
@end
@implementation LoginScreen
@ -36,6 +37,7 @@
[self.button setTitle:@"TRY AGAIN"];
}
[self.buildVersion setStringValue: [@"V." stringByAppendingString:@LAUNCHER_BUILD_VERSION]];
[self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]];
[self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]];

View file

@ -9,6 +9,7 @@
@property (nonatomic, assign) IBOutlet NSTextField* boldStatus;
@property (nonatomic, assign) IBOutlet NSTextField* smallStatus;
@property (nonatomic, assign) IBOutlet NSProgressIndicator* progressView;
@property (nonatomic, assign) IBOutlet NSTextField* buildVersion;
@end
@implementation ProcessScreen
@ -37,6 +38,7 @@
default:
break;
}
[self.buildVersion setStringValue: [@"V." stringByAppendingString:@LAUNCHER_BUILD_VERSION]];
[self.background setImage: [NSImage imageNamed:hifiBackgroundFilename]];
[self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]];
[self.voxelImage setImage: [NSImage imageNamed:hifiVoxelFilename]];

View file

@ -6,6 +6,7 @@
@property (nonatomic, assign) IBOutlet NSImageView* imageView;
@property (nonatomic, assign) IBOutlet NSImageView* logoImage;
@property (nonatomic, assign) IBOutlet NSButton* button;
@property (nonatomic, assign) IBOutlet NSTextField* buildVersion;
@end
@implementation SplashScreen
@ -15,5 +16,6 @@
-(void)awakeFromNib {
[self.imageView setImage:[NSImage imageNamed:hifiBackgroundFilename]];
[self.logoImage setImage:[NSImage imageNamed:hifiLargeLogoFilename]];
[self.buildVersion setStringValue: [@"V." stringByAppendingString:@LAUNCHER_BUILD_VERSION]];
}
@end

View file

@ -10,6 +10,7 @@ set(CMAKE_MFC_FLAG 1)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
include("cmake/macros/SetPackagingParameters.cmake")
add_executable(HQLauncher
WIN32
@ -49,6 +50,8 @@ function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
endif()
endfunction()
set_packaging_parameters()
set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "")
if (LAUNCHER_HMAC_SECRET STREQUAL "")
@ -56,7 +59,7 @@ if (LAUNCHER_HMAC_SECRET STREQUAL "")
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE LAUNCHER_HMAC_SECRET="${LAUNCHER_HMAC_SECRET}")
target_compile_definitions(${PROJECT_NAME} PRIVATE LAUNCHER_BUILD_VERSION="${BUILD_VERSION}")
# Preprocessor definitions
target_compile_definitions(HQLauncher PRIVATE

View file

@ -92,8 +92,8 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION
EXSTYLE WS_EX_APPWINDOW
FONT 10, "MS Shell Dlg", 400, 0, 0x0
BEGIN
CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,3,174,123, NOT WS_VISIBLE
CONTROL "", IDC_PROGRESS, "Static", SS_BLACKRECT, 35, 170, 239, 4, NOT WS_VISIBLE
CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,3,174,123
CONTROL "",IDC_PROGRESS,"Static",SS_BLACKRECT,35,170,239,4
EDITTEXT IDC_ORGNAME,44,68,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
EDITTEXT IDC_USERNAME,44,95,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
EDITTEXT IDC_PASSWORD,44,122,219,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
@ -107,6 +107,7 @@ BEGIN
RTEXT "",IDC_TERMS,15,172,180,15,NOT WS_VISIBLE
CONTROL "",IDC_TERMS_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,197,172,80,15
CTEXT "",IDC_TROUBLE,65,203,174,15,NOT WS_VISIBLE
RTEXT "",IDC_VERSION,100,205,205,10
CONTROL "NEXT",IDC_BUTTON_NEXT,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,107,158,94,16
CONTROL "Having Trouble?",IDC_TROUBLE_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,126,203,56,11
END

View file

@ -39,16 +39,28 @@ BOOL CLauncherApp::InitInstance() {
}
int iNumOfArgs;
LPWSTR* pArgs = CommandLineToArgvW(GetCommandLine(), &iNumOfArgs);
bool isUninstalling = false;
bool isRestarting = false;
bool uninstalling = false;
bool restarting = false;
bool noUpdate = false;
bool continueUpdating = false;
bool skipSplash = false;
if (iNumOfArgs > 1) {
if (CString(pArgs[1]).Compare(_T("--uninstall")) == 0) {
isUninstalling = true;
} else if (CString(pArgs[1]).Compare(_T("--restart")) == 0) {
isRestarting = true;
for (int i = 1; i < iNumOfArgs; i++) {
CString curArg = CString(pArgs[i]);
if (curArg.Compare(_T("--uninstall")) == 0) {
uninstalling = true;
} else if (curArg.Compare(_T("--restart")) == 0) {
restarting = true;
} else if (curArg.Compare(_T("--noUpdate")) == 0) {
noUpdate = true;
} else if (curArg.Compare(_T("--continueUpdating")) == 0) {
continueUpdating = true;
} else if (curArg.Compare(_T("--skipSplash")) == 0) {
skipSplash = true;
}
}
}
if (!isRestarting) {
if (!restarting) {
// don't launch if already running
CreateMutex(NULL, TRUE, _T("HQ_Launcher_Mutex"));
if (GetLastError() == ERROR_ALREADY_EXISTS) {
@ -56,10 +68,10 @@ BOOL CLauncherApp::InitInstance() {
}
}
if (isUninstalling) {
if (uninstalling) {
_manager.uninstall();
} else {
_manager.init();
_manager.init(!noUpdate, continueUpdating, skipSplash);
}
if (!_manager.hasFailed() && !_manager.installLauncher()) {
return FALSE;

View file

@ -40,6 +40,8 @@ static CString GRAPHIK_SEMIBOLD = _T("Graphik-Semibold");
static CString TROUBLE_URL = _T("https://www.highfidelity.com/hq-support");
static CString TERMS_URL = _T("https://www.highfidelity.com/termsofservice");
static int SPLASH_DURATION = 100;
CLauncherDlg::CLauncherDlg(CWnd* pParent)
: CDialog(IDD_LAUNCHER_DIALOG, pParent)
@ -112,6 +114,11 @@ BOOL CLauncherDlg::OnInitDialog() {
m_voxel = (CStatic *)GetDlgItem(IDC_VOXEL);
m_progress = (CStatic *)GetDlgItem(IDC_PROGRESS);
m_version = (CStatic *)GetDlgItem(IDC_VERSION);
CString version;
version.Format(_T("V.%s"), theApp._manager.getLauncherVersion());
m_version->SetWindowTextW(version);
m_voxel->EnableD2DSupport();
m_progress->EnableD2DSupport();
@ -230,7 +237,6 @@ void CLauncherDlg::startProcess() {
theApp._manager.setFailed(true);
}
});
}
BOOL CLauncherDlg::getHQInfo(const CString& orgname) {
@ -322,11 +328,12 @@ void CLauncherDlg::drawLogo(CHwndRenderTarget* pRenderTarget) {
void CLauncherDlg::drawSmallLogo(CHwndRenderTarget* pRenderTarget) {
CD2DBitmap m_pBitmamLogo(pRenderTarget, IDB_PNG5, _T("PNG"));
auto size = pRenderTarget->GetSize();
int padding = 6;
int xPadding = 6;
int yPadding = 22;
int logoWidth = 100;
int logoHeight = 18;
float logoPosX = size.width - logoWidth - padding;
float logoPosY = size.height - logoHeight - padding;
float logoPosX = size.width - logoWidth - xPadding;
float logoPosY = size.height - logoHeight - yPadding;
CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight);
pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec);
}
@ -521,6 +528,7 @@ BOOL CLauncherDlg::getTextFormat(int resID, TextFormat& formatOut) {
formatOut.size = FIELDS_FONT_SIZE;
formatOut.color = COLOR_GREY;
break;
case IDC_VERSION:
case IDC_TERMS:
formatOut.size = TERMS_FONT_SIZE;
break;
@ -663,16 +671,46 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
// Refresh
setDrawDialog(_drawStep, true);
}
if (theApp._manager.needsSelfUpdate()) {
if (theApp._manager.needsSelfDownload()) {
theApp._manager.downloadNewLauncher();
} else {
if (_splashStep > SPLASH_DURATION && _splashStep < 2 * SPLASH_DURATION) {
float progress = (float)(_splashStep - SPLASH_DURATION) / SPLASH_DURATION;
if (theApp._manager.willContinueUpdating()) {
progress = CONTINUE_UPDATING_GLOBAL_OFFSET * progress;
progress = min(progress, CONTINUE_UPDATING_GLOBAL_OFFSET);
}
theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, progress);
_splashStep++;
}
if (theApp._manager.needsRestartNewLauncher()) {
if (_splashStep >= 2 * SPLASH_DURATION) {
theApp._manager.restartNewLauncher();
exit(0);
}
}
}
}
if (_showSplash) {
if (_splashStep == 0) {
if (theApp._manager.needsUninstall()) {
theApp._manager.addToLog(_T("Waiting to uninstall"));
setDrawDialog(DrawStep::DrawProcessUninstall);
} else if (theApp._manager.shouldContinueUpdating()) {
_splashStep = SPLASH_DURATION;
setDrawDialog(DrawStep::DrawProcessUpdate);
theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 0.0f);
} else {
theApp._manager.addToLog(_T("Start splash screen"));
setDrawDialog(DrawStep::DrawLogo);
if (theApp._manager.shouldSkipSplashScreen()) {
_splashStep = SPLASH_DURATION;
} else {
theApp._manager.addToLog(_T("Start splash screen"));
setDrawDialog(DrawStep::DrawLogo);
}
}
} else if (_splashStep > 100 && !theApp._manager.needsToWait()) {
} else if (_splashStep > SPLASH_DURATION && !theApp._manager.needsToWait()) {
_showSplash = false;
if (theApp._manager.shouldShutDown()) {
if (_applicationWND != NULL) {
@ -692,12 +730,14 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
theApp._manager.addToLog(_T("HQ failed to uninstall."));
theApp._manager.setFailed(true);
}
} else if (theApp._manager.needsSelfUpdate()) {
setDrawDialog(DrawStep::DrawProcessUpdate);
} else {
theApp._manager.addToLog(_T("Starting login"));
setDrawDialog(DrawStep::DrawLoginLogin);
}
} else if (theApp._manager.needsUninstall()) {
theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, (float)_splashStep/100);
theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, (float)_splashStep / SPLASH_DURATION);
}
_splashStep++;
} else if (theApp._manager.shouldShutDown()) {
@ -741,12 +781,17 @@ void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) {
auto m_voxelRenderTarget = m_voxel->GetRenderTarget();
auto m_progressRenderTarget = m_progress->GetRenderTarget();
switch (_drawStep) {
case DrawStep::DrawLogo:
case DrawStep::DrawLogo: {
m_pRenderTarget->BeginDraw();
drawBackground(m_pRenderTarget);
drawLogo(m_pRenderTarget);
m_pRenderTarget->EndDraw();
CRect redrawRec;
GetClientRect(redrawRec);
redrawRec.top = redrawRec.bottom - 30;
RedrawWindow(redrawRec);
break;
}
case DrawStep::DrawLoginLogin:
case DrawStep::DrawLoginErrorOrg:
case DrawStep::DrawLoginErrorCred:

View file

@ -94,6 +94,8 @@ protected:
CStatic* m_username_banner;
CStatic* m_password_banner;
CStatic* m_version;
HWND _applicationWND { 0 };
void drawBackground(CHwndRenderTarget* pRenderTarget);

View file

@ -21,10 +21,20 @@ LauncherManager::LauncherManager() {
LauncherManager::~LauncherManager() {
}
void LauncherManager::init() {
void LauncherManager::init(BOOL allowUpdate, BOOL continueUpdating, BOOL skipSplashScreen) {
initLog();
addToLog(_T("Getting most recent build"));
getMostRecentBuild(_latestApplicationURL, _latestVersion);
int tokenPos = 0;
_updateLauncherAllowed = allowUpdate;
_continueUpdating = continueUpdating;
_skipSplashScreen = skipSplashScreen;
_shouldWait = !skipSplashScreen;
if (_continueUpdating) {
_progressOffset = CONTINUE_UPDATING_GLOBAL_OFFSET;
}
_launcherVersion = CString(LAUNCHER_BUILD_VERSION).Tokenize(_T("-"), tokenPos);
addToLog(_T("Launcher is running version: " + _launcherVersion));
addToLog(_T("Getting most recent builds"));
getMostRecentBuilds(_latestLauncherURL, _latestLauncherVersion, _latestApplicationURL, _latestVersion);
}
BOOL LauncherManager::initLog() {
@ -124,6 +134,8 @@ BOOL LauncherManager::restartLauncher() {
void LauncherManager::updateProgress(ProcessType processType, float progress) {
switch (processType) {
case ProcessType::DownloadLauncher:
break;
case ProcessType::Uninstall:
_progress = progress;
break;
@ -153,6 +165,7 @@ void LauncherManager::updateProgress(ProcessType processType, float progress) {
default:
break;
}
_progress = _progressOffset + (1.0f - _progressOffset) * _progress;
TRACE("progress = %f\n", _progress);
}
@ -200,11 +213,11 @@ BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain,
CString applicationDir;
getAndCreatePaths(PathType::Launcher_Directory, applicationDir);
CString applicationPath = applicationDir + "interface\\interface.exe";
BOOL isApplicationInstalled = PathFileExistsW(applicationPath);
BOOL isInstalled = PathFileExistsW(applicationPath);
BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json"));
if (configFileExist) {
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn);
return isApplicationInstalled && status == LauncherUtils::ResponseError::NoError;
return isInstalled && status == LauncherUtils::ResponseError::NoError;
}
return FALSE;
}
@ -359,14 +372,23 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
return LauncherUtils::ResponseError::ParsingJSON;
}
void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& launcherVersionOut,
CString& interfaceUrlOut, CString& interfaceVersionOut) {
CString contentTypeJson = L"content-type:application/json";
std::function<void(CString, int)> httpCallback = [&](CString response, int err) {
LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err);
if (error == LauncherUtils::ResponseError::NoError) {
Json::Value json;
error = LauncherUtils::ResponseError::ParsingJSON;
if (LauncherUtils::parseJSON(response, json)) {
if (json["launcher"].isObject()) {
if (json["launcher"]["windows"].isObject() && json["launcher"]["windows"]["url"].isString()) {
launcherUrlOut = json["launcher"]["windows"]["url"].asCString();
}
if (json["launcher"]["version"].isInt()) {
std::string version = std::to_string(json["launcher"]["version"].asInt());
launcherVersionOut = CString(version.c_str());
}
}
int count = json["count"].isInt() ? json["count"].asInt() : 0;
if (count > 0 && json["results"].isArray()) {
for (int i = 0; i < count; i++) {
@ -374,20 +396,22 @@ void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
Json::Value result = json["results"][i];
if (result["latest_version"].isInt()) {
std::string version = std::to_string(result["latest_version"].asInt());
versionOut = CString(version.c_str());
interfaceVersionOut = CString(version.c_str());
}
if (result["installers"].isObject() &&
result["installers"]["windows"].isObject() &&
result["installers"]["windows"]["zip_url"].isString()) {
urlOut = result["installers"]["windows"]["zip_url"].asCString();
error = LauncherUtils::ResponseError::NoError;
interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString();
}
}
}
}
if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty() || interfaceUrlOut.IsEmpty() || interfaceVersionOut.IsEmpty()) {
error = LauncherUtils::ResponseError::ParsingJSON;
}
}
onMostRecentBuildReceived(response, error);
}
onMostRecentBuildsReceived(response, error);
};
LauncherUtils::httpCallOnThread(L"HQ Launcher",
L"thunder.highfidelity.com",
@ -395,31 +419,49 @@ void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
contentTypeJson, CStringA(), false, httpCallback);
}
void LauncherManager::onMostRecentBuildReceived(const CString& response, LauncherUtils::ResponseError error) {
void LauncherManager::onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error) {
if (error == LauncherUtils::ResponseError::NoError) {
addToLog(_T("Latest version: ") + _latestVersion);
addToLog(_T("Latest launcher version: ") + _latestLauncherVersion);
CString currentVersion;
if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) {
addToLog(_T("Installed version: ") + currentVersion);
if (_latestVersion.Compare(currentVersion) == 0) {
addToLog(_T("Already running most recent build. Launching interface.exe"));
_shouldLaunch = TRUE;
_shouldShutdown = TRUE;
} else {
addToLog(_T("New build found. Updating"));
_shouldUpdate = TRUE;
}
} else if (_loggedIn) {
addToLog(_T("Interface not found but logged in. Reinstalling"));
_shouldUpdate = TRUE;
BOOL isInstalled = (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn);
bool newInterfaceVersion = _latestVersion.Compare(currentVersion) != 0;
bool newLauncherVersion = _latestLauncherVersion.Compare(_launcherVersion) != 0 && _updateLauncherAllowed;
if (newLauncherVersion) {
CString updatingMsg;
updatingMsg.Format(_T("Updating Launcher from version: %s to version: %s"), _launcherVersion, _latestLauncherVersion);
addToLog(updatingMsg);
_shouldUpdateLauncher = TRUE;
_shouldDownloadLauncher = TRUE;
_willContinueUpdating = isInstalled && newInterfaceVersion;
} else {
_shouldInstall = TRUE;
if (_updateLauncherAllowed) {
addToLog(_T("Already running most recent build. Launching interface.exe"));
} else {
addToLog(_T("Updating the launcher was not allowed --noUpdate"));
}
if (isInstalled) {
addToLog(_T("Installed version: ") + currentVersion);
if (!newInterfaceVersion) {
addToLog(_T("Already running most recent build. Launching interface.exe"));
_shouldLaunch = TRUE;
_shouldShutdown = TRUE;
} else {
addToLog(_T("New build found. Updating"));
_shouldUpdate = TRUE;
}
} else if (_loggedIn) {
addToLog(_T("Interface not found but logged in. Reinstalling"));
_shouldUpdate = TRUE;
} else {
_shouldInstall = TRUE;
}
}
_shouldWait = FALSE;
} else {
_hasFailed = true;
CString msg;
msg.Format(_T("Getting most recent build has failed with error: %d"), error);
msg.Format(_T("Getting most recent builds has failed with error: %d"), error);
addToLog(msg);
msg.Format(_T("Response: %s"), response);
addToLog(msg);
@ -521,7 +563,7 @@ BOOL LauncherManager::extractApplication() {
}
};
std::function<void(float)> onProgress = [&](float progress) {
updateProgress(ProcessType::UnzipApplication, progress);
updateProgress(ProcessType::UnzipApplication, max(progress, 0.0f));
};
_currentProcess = ProcessType::UnzipApplication;
BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipApplication,
@ -563,9 +605,21 @@ void LauncherManager::onFileDownloaded(ProcessType type) {
setFailed(true);
}
});
} else if (type == ProcessType::DownloadLauncher) {
_shouldRestartNewLauncher = true;
}
}
void LauncherManager::restartNewLauncher() {
closeLog();
if (_willContinueUpdating) {
LauncherUtils::launchApplication(_tempLauncherPath, _T(" --restart --noUpdate --continueUpdating"));
} else {
LauncherUtils::launchApplication(_tempLauncherPath, _T(" --restart --noUpdate --skipSplash"));
}
Sleep(500);
}
BOOL LauncherManager::installContent() {
std::string contentZipFile = LauncherUtils::cStringToStd(_contentZipPath);
@ -582,7 +636,7 @@ BOOL LauncherManager::installContent() {
}
};
std::function<void(float)> onProgress = [&](float progress) {
updateProgress(ProcessType::UnzipContent, progress);
updateProgress(ProcessType::UnzipContent, max(progress, 0.0f));
};
_currentProcess = ProcessType::UnzipContent;
BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipContent, contentZipFile,
@ -597,10 +651,13 @@ BOOL LauncherManager::installContent() {
BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString& outPath) {
CString fileName = url.Mid(url.ReverseFind('/') + 1);
CString downloadDirectory;
BOOL success = getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDirectory);
outPath = downloadDirectory + fileName;
BOOL success = TRUE;
if (outPath.IsEmpty()) {
CString fileName = url.Mid(url.ReverseFind('/') + 1);
CString downloadDirectory;
BOOL success = getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDirectory);
outPath = downloadDirectory + fileName;
}
_currentProcess = type;
if (success) {
addToLog(_T("Downloading: ") + url);
@ -610,18 +667,18 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString
} else {
if (type == ProcessType::DownloadApplication) {
addToLog(_T("Error downloading content."));
} else if (type == ProcessType::DownloadLauncher) {
addToLog(_T("Error downloading launcher."));
} else {
addToLog(_T("Error downloading application."));
}
_hasFailed = true;
}
};
std::function<void(float)> onProgress = [&](float progress) {
updateProgress(_currentProcess, progress);
std::function<void(float)> onProgress = [&, type](float progress) {
updateProgress(_currentProcess, max(progress, 0.0f));
};
if (!LauncherUtils::downloadFileOnThread(type, url, outPath, onDownloadFinished, onProgress)) {
success = FALSE;
}
success = LauncherUtils::downloadFileOnThread(type, url, outPath, onDownloadFinished, onProgress);
}
return success;
}
@ -637,6 +694,14 @@ BOOL LauncherManager::downloadApplication() {
return downloadFile(ProcessType::DownloadApplication, applicationURL, _applicationZipPath);
}
BOOL LauncherManager::downloadNewLauncher() {
_shouldDownloadLauncher = FALSE;
getAndCreatePaths(PathType::Temp_Directory, _tempLauncherPath);
CString tempName = _T("HQLauncher") + _launcherVersion + _T(".exe");
_tempLauncherPath += tempName;
return downloadFile(ProcessType::DownloadLauncher, _latestLauncherURL, _tempLauncherPath);
}
void LauncherManager::onCancel() {
if (_currentProcess == ProcessType::UnzipApplication) {
_latestVersion = _T("");

View file

@ -25,6 +25,7 @@ const float DOWNLOAD_APPLICATION_INSTALL_WEIGHT = 0.5f;
const float EXTRACT_APPLICATION_INSTALL_WEIGHT = 0.2f;
const float DOWNLOAD_APPLICATION_UPDATE_WEIGHT = 0.75f;
const float EXTRACT_APPLICATION_UPDATE_WEIGHT = 0.25f;
const float CONTINUE_UPDATING_GLOBAL_OFFSET = 0.2f;
class LauncherManager
{
@ -49,6 +50,7 @@ public:
ErrorIOFiles
};
enum ProcessType {
DownloadLauncher = 0,
DownloadContent,
DownloadApplication,
UnzipContent,
@ -57,7 +59,7 @@ public:
};
LauncherManager();
~LauncherManager();
void init();
void init(BOOL allowUpdate, BOOL continueUpdating, BOOL skipSplashScreen);
BOOL initLog();
BOOL addToLog(const CString& line);
void closeLog();
@ -67,7 +69,8 @@ public:
BOOL isApplicationInstalled(CString& version, CString& domain,
CString& content, bool& loggedIn);
LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
void getMostRecentBuild(CString& urlOut, CString& versionOut);
void getMostRecentBuilds(CString& launcherUrlOut, CString& launcherVersionOut,
CString& interfaceUrlOut, CString& interfaceVersionOut);
LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
CString& content, bool& loggedIn);
@ -87,13 +90,19 @@ public:
const CString& getVersion() const { return _version; }
BOOL shouldShutDown() const { return _shouldShutdown; }
BOOL shouldLaunch() const { return _shouldLaunch; }
BOOL needsUpdate() { return _shouldUpdate; }
BOOL needsUninstall() { return _shouldUninstall; }
BOOL needsInstall() { return _shouldInstall; }
BOOL needsToWait() { return _shouldWait; }
BOOL shouldSkipSplashScreen() const { return _skipSplashScreen; }
BOOL needsUpdate() const { return _shouldUpdate; }
BOOL needsSelfUpdate() const { return _shouldUpdateLauncher; }
BOOL needsSelfDownload() const { return _shouldDownloadLauncher; }
BOOL needsUninstall() const { return _shouldUninstall; }
BOOL needsInstall() const { return _shouldInstall; }
BOOL needsToWait() const { return _shouldWait; }
BOOL needsRestartNewLauncher() const { return _shouldRestartNewLauncher; }
BOOL shouldContinueUpdating() const { return _continueUpdating; }
BOOL willContinueUpdating() const { return _willContinueUpdating; }
void setDisplayName(const CString& displayName) { _displayName = displayName; }
bool isLoggedIn() { return _loggedIn; }
bool hasFailed() { return _hasFailed; }
bool isLoggedIn() const { return _loggedIn; }
bool hasFailed() const { return _hasFailed; }
void setFailed(bool hasFailed) { _hasFailed = hasFailed; }
const CString& getLatestInterfaceURL() const { return _latestApplicationURL; }
void uninstall() { _shouldUninstall = true; _shouldWait = false; };
@ -101,19 +110,24 @@ public:
BOOL downloadFile(ProcessType type, const CString& url, CString& localPath);
BOOL downloadContent();
BOOL downloadApplication();
BOOL downloadNewLauncher();
BOOL installContent();
BOOL extractApplication();
void restartNewLauncher();
void onZipExtracted(ProcessType type, int size);
void onFileDownloaded(ProcessType type);
float getProgress() { return _progress; }
float getProgress() const { return _progress; }
void updateProgress(ProcessType processType, float progress);
void onCancel();
const CString& getLauncherVersion() const { return _launcherVersion; }
private:
ProcessType _currentProcess { ProcessType::DownloadApplication };
void onMostRecentBuildReceived(const CString& response, LauncherUtils::ResponseError error);
void onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error);
CString _latestApplicationURL;
CString _latestVersion;
CString _latestLauncherURL;
CString _latestLauncherVersion;
CString _contentURL;
CString _domainURL;
CString _version;
@ -121,6 +135,8 @@ private:
CString _tokensJSON;
CString _applicationZipPath;
CString _contentZipPath;
CString _launcherVersion;
CString _tempLauncherPath;
bool _loggedIn { false };
bool _hasFailed { false };
BOOL _shouldUpdate { FALSE };
@ -129,6 +145,14 @@ private:
BOOL _shouldShutdown { FALSE };
BOOL _shouldLaunch { FALSE };
BOOL _shouldWait { TRUE };
BOOL _shouldUpdateLauncher { FALSE };
BOOL _shouldDownloadLauncher { FALSE };
BOOL _updateLauncherAllowed { TRUE };
BOOL _shouldRestartNewLauncher { FALSE };
BOOL _continueUpdating { FALSE };
BOOL _willContinueUpdating { FALSE };
BOOL _skipSplashScreen { FALSE };
float _progressOffset { 0.0f };
float _progress { 0.0f };
CStdioFile _logFile;
};

View file

@ -0,0 +1,45 @@
#
# SetPackagingParameters.cmake
# cmake/macros
#
# Created by Leonardo Murillo on 07/14/2015.
# Copyright 2015 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
# This macro checks some Jenkins defined environment variables to determine the origin of this build
# and decides how targets should be packaged.
macro(SET_PACKAGING_PARAMETERS)
set(PR_BUILD 0)
set(PRODUCTION_BUILD 0)
set(DEV_BUILD 0)
set(BUILD_NUMBER 0)
set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV")
set_from_env(RELEASE_NUMBER RELEASE_NUMBER "")
set_from_env(STABLE_BUILD STABLE_BUILD 0)
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
set(BUILD_NUMBER ${RELEASE_NUMBER})
if (RELEASE_TYPE STREQUAL "PRODUCTION")
set(PRODUCTION_BUILD 1)
set(BUILD_VERSION ${RELEASE_NUMBER})
# add definition for this release type
add_definitions(-DPRODUCTION_BUILD)
elseif (RELEASE_TYPE STREQUAL "PR")
set(PR_BUILD 1)
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
# add definition for this release type
add_definitions(-DPR_BUILD)
else ()
set(DEV_BUILD 1)
set(BUILD_VERSION "dev")
endif ()
endmacro(SET_PACKAGING_PARAMETERS)

View file

@ -27,6 +27,7 @@
#define IDC_TROUBLE 1023
#define IDC_VOXEL 1024
#define IDC_PROGRESS 1025
#define IDC_VERSION 1026
#define IDC_TROUBLE_LINK 1027
// Next default values for new objects

View file

@ -1092,6 +1092,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::Takeoff;
} else if (ccState == CharacterControllerState::Seated) {
if (_desiredState != RigRole::Seated) {
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::Seated;
} else {
float moveThresh;
if (_state != RigRole::Move) {
@ -1216,6 +1221,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInAirStand", false);
_animVars.set("isInAirRun", false);
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
} else if (_state == RigRole::Turn) {
if (turningSpeed > 0.0f) {
@ -1244,6 +1250,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInAirStand", false);
_animVars.set("isInAirRun", false);
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
} else if (_state == RigRole::Idle) {
// default anim vars to notMoving and notTurning
@ -1265,6 +1272,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInAirStand", false);
_animVars.set("isInAirRun", false);
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
} else if (_state == RigRole::Hover) {
// flying.
@ -1286,6 +1294,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInAirStand", false);
_animVars.set("isInAirRun", false);
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
} else if (_state == RigRole::Takeoff) {
// jumping in-air
@ -1315,6 +1324,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInAirStand", false);
_animVars.set("isInAirRun", false);
_animVars.set("isNotInAir", false);
_animVars.set("isSeated", false);
} else if (_state == RigRole::InAir) {
// jumping in-air
@ -1333,6 +1343,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isTakeoffStand", false);
_animVars.set("isTakeoffRun", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isSeated", false);
bool inAirRun = forwardSpeed > 0.1f;
if (inAirRun) {
@ -1354,6 +1365,26 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
float alpha = glm::clamp((-workingVelocity.y * sensorToWorldScale) / jumpSpeed, -1.0f, 1.0f) + 1.0f;
_animVars.set("inAirAlpha", alpha);
} else if (_state == RigRole::Seated) {
_animVars.set("isMovingForward", false);
_animVars.set("isMovingBackward", false);
_animVars.set("isMovingRight", false);
_animVars.set("isMovingLeft", false);
_animVars.set("isMovingRightHmd", false);
_animVars.set("isMovingLeftHmd", false);
_animVars.set("isNotMoving", false);
_animVars.set("isTurningRight", false);
_animVars.set("isTurningLeft", false);
_animVars.set("isNotTurning", true);
_animVars.set("isFlying", false);
_animVars.set("isNotFlying", true);
_animVars.set("isTakeoffStand", false);
_animVars.set("isTakeoffRun", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isInAirStand", false);
_animVars.set("isInAirRun", false);
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", true);
}
t += deltaTime;
@ -1873,6 +1904,61 @@ void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabl
}
}
void Rig::updateReactions(const ControllerParameters& params) {
// enable/disable animVars
bool enabled = params.reactionEnabledFlags[AVATAR_REACTION_POSITIVE];
_animVars.set("reactionPositiveEnabled", enabled);
_animVars.set("reactionPositiveDisabled", !enabled);
enabled = params.reactionEnabledFlags[AVATAR_REACTION_NEGATIVE];
_animVars.set("reactionNegativeEnabled", enabled);
_animVars.set("reactionNegativeDisabled", !enabled);
enabled = params.reactionEnabledFlags[AVATAR_REACTION_RAISE_HAND];
_animVars.set("reactionRaiseHandEnabled", enabled);
_animVars.set("reactionRaiseHandDisabled", !enabled);
enabled = params.reactionEnabledFlags[AVATAR_REACTION_APPLAUD];
_animVars.set("reactionApplaudEnabled", enabled);
_animVars.set("reactionApplaudDisabled", !enabled);
enabled = params.reactionEnabledFlags[AVATAR_REACTION_POINT];
_animVars.set("reactionPointEnabled", enabled);
_animVars.set("reactionPointDisabled", !enabled);
// trigger animVars
if (params.reactionTriggers[AVATAR_REACTION_POSITIVE]) {
_animVars.set("reactionPositiveTrigger", true);
} else {
_animVars.set("reactionPositiveTrigger", false);
}
if (params.reactionTriggers[AVATAR_REACTION_NEGATIVE]) {
_animVars.set("reactionNegativeTrigger", true);
} else {
_animVars.set("reactionNegativeTrigger", false);
}
if (params.reactionTriggers[AVATAR_REACTION_RAISE_HAND]) {
_animVars.set("reactionRaiseHandTrigger", true);
} else {
_animVars.set("reactionRaiseHandTrigger", false);
}
if (params.reactionTriggers[AVATAR_REACTION_APPLAUD]) {
_animVars.set("reactionApplaudTrigger", true);
} else {
_animVars.set("reactionApplaudTrigger", false);
}
if (params.reactionTriggers[AVATAR_REACTION_POINT]) {
_animVars.set("reactionPointTrigger", true);
} else {
_animVars.set("reactionPointTrigger", false);
}
}
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
// TODO: does not properly handle avatar scale.
@ -2152,6 +2238,8 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
}
}
updateReactions(params);
_previousControllerParameters = params;
}

View file

@ -88,6 +88,8 @@ public:
AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space
uint8_t secondaryControllerFlags[NumSecondaryControllerTypes];
bool isTalking;
bool reactionEnabledFlags[NUM_AVATAR_REACTIONS];
bool reactionTriggers[NUM_AVATAR_REACTIONS];
HFMJointShapeInfo hipsShapeInfo;
HFMJointShapeInfo spineShapeInfo;
HFMJointShapeInfo spine1ShapeInfo;
@ -107,7 +109,8 @@ public:
Ground = 0,
Takeoff,
InAir,
Hover
Hover,
Seated
};
Rig();
@ -268,6 +271,7 @@ protected:
void updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabled,
const AnimPose& leftFootPose, const AnimPose& rightFootPose,
const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix);
void updateReactions(const ControllerParameters& params);
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAt, const glm::vec3& saccade);
void calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const;
@ -336,7 +340,8 @@ protected:
Move,
Hover,
Takeoff,
InAir
InAir,
Seated
};
RigRole _state { RigRole::Idle };
RigRole _desiredState { RigRole::Idle };

View file

@ -2861,7 +2861,7 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const
* Information on an attachment worn by the avatar.
* @typedef {object} AttachmentData
* @property {string} modelUrl - The URL of the model file. Models can be FBX or OBJ format.
* @property {string} jointName - The offset to apply to the model relative to the joint position.
* @property {string} jointName - The name of the joint that the attachment is parented to.
* @property {Vec3} translation - The offset from the joint that the attachment is positioned at.
* @property {Vec3} rotation - The rotation applied to the model relative to the joint orientation.
* @property {number} scale - The scale applied to the attachment model.

View file

@ -1292,7 +1292,7 @@ public:
* jointName: "Head",
* translation: {"x": 0, "y": 0.25, "z": 0},
* rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
* scale: 1,
* scale: 0.01,
* isSoft: false
* };
*

View file

@ -174,20 +174,35 @@ private:
};
/**jsdoc
* The <code>Reticle</code> API provides access to the mouse cursor. The cursor may be an arrow or a reticle circle, depending
* on Interface settings. The mouse cursor is visible in HMD mode if controllers aren't being used.
*
* @namespace Reticle
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {boolean} allowMouseCapture
* @property {number} depth
* @property {Vec2} maximumPosition
* @property {boolean} mouseCaptured
* @property {boolean} pointingAtSystemOverlay
* @property {Vec2} position
* @property {number} scale
* @property {boolean} visible
* @property {boolean} allowMouseCapture=true - <code>true</code> if the mouse cursor will be captured when in HMD mode and the
* Interface window content (excluding menus) has focus, <code>false</code> if the mouse cursor will not be captured.
* @property {number} depth - The depth (distance) that the reticle is displayed at relative to the HMD view, in HMD mode.
* @property {Vec2} maximumPosition - The maximum reticle coordinates on the display device in desktop mode or the HUD surface
* in HMD mode. (The minimum reticle coordinates on the desktop display device or HUD surface are <code>0</code>,
* <code>0</code>.) <em>Read-only.</em>
* @property {boolean} mouseCaptured - <code>true</code> if the mouse cursor is captured, displaying only in Interface and
* not on the rest of the desktop. The mouse cursor may be captured when in HMD mode and the Interface window content
* (excluding menu items) has focus, if capturing is enabled (<code>allowMouseCapture</code> is <code>true</code>).
* <em>Read-only.</em>
* @property {boolean} pointingAtSystemOverlay - <code>true</code> if the mouse cursor is pointing at UI in the Interface
* window in desktop mode or on the HUD surface in HMD mode, <code>false</code> if it isn't. <em>Read-only.</em>
* @property {Vec2} position - The position of the cursor. This is the position relative to the Interface window in desktop
* mode, and the HUD surface in HMD mode.
* <p><strong>Note:</strong> The position values may be negative.</p>
* @property {number} scale=1 - The scale of the reticle circle in desktop mode, and the arrow and reticle circle in HMD mode.
* (Does not affect the size of the arrow in desktop mode.)
* @property {boolean} visible=true - <code>true</code> if the reticle circle is visible in desktop mode, and the arrow or
* reticle circle are visible in HMD mode; <code>false</code> otherwise. (Does not affect the visibility of the mouse
* pointer in desktop mode.)
*/
// Scripting interface available to control the Reticle
class ReticleInterface : public QObject {
@ -205,80 +220,113 @@ public:
ReticleInterface(CompositorHelper* outer) : QObject(outer), _compositor(outer) {}
/**jsdoc
* Checks whether the mouse cursor is captured, displaying only in Interface and not on the rest of the desktop. The mouse
* cursor is captured when in HMD mode and the Interface window content (excluding menu items) has focus, if capturing is
* enabled (<code>allowMouseCapture</code> property value is <code>true</code>).
* @function Reticle.isMouseCaptured
* @returns {boolean}
* @returns {boolean} <code>true</code> if the mouse cursor is captured, displaying only in Interface and not on the
* desktop.
*/
Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); }
/**jsdoc
* Gets whether the mouse cursor will be captured when in HMD mode and the Interface window content (excluding menu items)
* has focus. When captured, the mouse cursor displays only in Interface, not on the rest of the desktop.
* @function Reticle.getAllowMouseCapture
* @returns {boolean}
* @returns {boolean} <code>true</code> if the mouse cursor will be captured when in HMD mode and the Interface window
* content has focus, <code>false</code> if the mouse cursor will not be captured.
*/
Q_INVOKABLE bool getAllowMouseCapture() { return _compositor->getAllowMouseCapture(); }
/**jsdoc
* Sets whether the mouse cursor will be captured when in HMD mode and the Interface window content (excluding menu items)
* has focus. When captured, the mouse cursor displays only in Interface, not on the rest of desktop.
* @function Reticle.setAllowMouseCapture
* @param {boolean} allowMouseCaptured
* @param {boolean} allowMouseCaptured - <code>true</code> if the mouse cursor will be captured when in HMD mode and the
* Interface window content has focus, <code>false</code> if the mouse cursor will not be captured.
*/
Q_INVOKABLE void setAllowMouseCapture(bool value) { return _compositor->setAllowMouseCapture(value); }
/**jsdoc
* Gets whether the mouse cursor is pointing at UI in the Interface window in desktop mode or on the HUD surface in HMD
* mode.
* @function Reticle.isPointingAtSystemOverlay
* @returns {boolean}
* @returns {boolean} <code>true</code> if the mouse cursor is pointing at UI in the Interface window in desktop mode or on
* the HUD surface in HMD mode, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); }
/**jsdoc
* Gets whether the reticle circle is visible in desktop mode, or the arrow or reticle circle are visible in HMD mode.
* @function Reticle.getVisible
* @returns {boolean}
* @returns {boolean} <code>true</code> if the reticle circle is visible in desktop mode, and the arrow or
* reticle circle are visible in HMD mode; <code>false</code> otherwise. (The mouse pointer is always visible in
* desktop mode.)
*/
Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); }
/**jsdoc
* Sets whether the reticle circle is visible in desktop mode, or the arrow or reticle circle are visible in HMD mode.
* @function Reticle.setVisible
* @param {boolean} visible
* @param {boolean} visible - <code>true</code> if the reticle circle is visible in desktop mode, and the arrow or reticle
* circle are visible in HMD mode; <code>false</code> otherwise. (Does not affect the visibility of the mouse pointer
* in desktop mode.)
*/
Q_INVOKABLE void setVisible(bool visible) { _compositor->setReticleVisible(visible); }
/**jsdoc
* Gets the depth (distance) that the reticle is displayed at relative to the HMD view, in HMD mode.
* @function Reticle.getDepth
* @returns {number}
* @returns {number} The depth (distance) that the reticle is displayed at relative to the HMD view, in HMD mode.
*/
Q_INVOKABLE float getDepth() { return _compositor->getReticleDepth(); }
/**jsdoc
* Sets the depth (distance) that the reticle is displayed at relative to the HMD view, in HMD mode.
* @function Reticle.setDepth
* @param {number} depth
* @param {number} depth - The depth (distance) that the reticle is displayed at relative to the HMD view, in HMD mode.
*/
Q_INVOKABLE void setDepth(float depth) { _compositor->setReticleDepth(depth); }
/**jsdoc
* Gets the scale of the reticle circle in desktop mode, and the arrow and reticle circle in HMD mode. (Does not affect the
* size of the arrow in desktop mode.) The default scale is <code>1.0</code>.
* @function Reticle.getScale
* @returns {number}
* @returns {number} The scale of the reticle.
*/
Q_INVOKABLE float getScale() const;
/**jsdoc
* Sets the scale of the reticle circle in desktop mode, and the arrow and reticle circle in HMD mode. (Does not affect the
* size of the arrow in desktop mode.) The default scale is <code>1.0</code>.
* @function Reticle.setScale
* @param {number} scale
* @param {number} scale - The scale of the reticle.
*/
Q_INVOKABLE void setScale(float scale);
/**jsdoc
* Gets the position of the cursor. This is the position relative to the Interface window in desktop mode, and the HUD
* surface in HMD mode.
* <p><strong>Note:</strong> The position values may be negative.</p>
* @function Reticle.getPosition
* @returns {Vec2}
* @returns {Vec2} The position of the cursor.
*/
Q_INVOKABLE QVariant getPosition() const;
/**jsdoc
* Sets the position of the cursor. This is the position relative to the Interface window in desktop mode, and the HUD
* surface in HMD mode.
* <p><strong>Note:</strong> The position values may be negative.</p>
* @function Reticle.setPosition
* @param {Vec2} position
* @param {Vec2} position - The position of the cursor.
*/
Q_INVOKABLE void setPosition(QVariant position);
/**jsdoc
* Gets the maximum reticle coordinates on the display device in desktop mode or the HUD surface in HMD mode. (The minimum
* reticle coordinates on the desktop display device or HUD surface are <code>0</code>, <code>0</code>.)
* @function Reticle.getMaximumPosition
* @returns {Vec2}
* @returns {Vec2} The maximum reticle coordinates on the display device in desktop mode or the HUD surface in HMD mode.
*/
Q_INVOKABLE glm::vec2 getMaximumPosition() { return _compositor->getReticleMaximumPosition(); }

View file

@ -988,8 +988,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* <code>false</code> otherwise; <code>[]</code> if none are applied or the model hasn't loaded. The array indexes are per
* {@link Entities.getJointIndex|getJointIndex}.
* @property {Vec3[]} jointTranslations=[]] - Joint translations applied to the model; <code>[]</code> if none are applied or
* the model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Rotations are relative
* to each joint's parent.
* the model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Translations are
* relative to each joint's parent.
* <p>Joint translations can be set by {@link Entities.setLocalJointTranslation|setLocalJointTranslation} and similar
* functions, or by setting the value of this property. If you set a joint translation using this property you also need to
* set the corresponding <code>jointTranslationsSet</code> value to <code>true</code>.</p>

View file

@ -446,7 +446,15 @@ public slots:
/**jsdoc
* Gets an entity's script object. In particular, this is useful for accessing a {@link Entities.EntityProperties-Web|Web}
* entity's HTML <code>EventBridge</code> script object to exchange messages with the web page script.
* <p>Alternatively, you can use {@link Entities.emitScriptEvent} and {@link Entities.webEventReceived} to exchange
* <p>To send a message from an Interface script to a Web entity over its event bridge:</p>
* <pre class="prettyprint"><code>var entityObject = Entities.getEntityObject(entityID);
* entityObject.emitScriptEvent(message);</code></pre>
* <p>To receive a message from a Web entity over its event bridge in an Interface script:</p>
* <pre class="prettyprint"><code>var entityObject = Entities.getentityObject(entityID);
* entityObject.webEventReceived.connect(function(message) {
* ...
* };</code></pre>
* <p>Alternatively, you can use {@link Entities.emitScriptEvent} and {@link Entities.webEventReceived} to exchange
* messages with a Web entity over its event bridge.</p>
* @function Entities.getEntityObject
* @param {Uuid} id - The ID of the entity to get the script object for.
@ -459,7 +467,7 @@ public slots:
* <title>HELLO</title>
* </head>
* <body>
* <h1>HELLO</h1></h1>
* <h1>HELLO</h1>
* <script>
* function onScriptEventReceived(message) {
* // Message received from the script.
@ -476,7 +484,7 @@ public slots:
* </body>
* </html>
*
* // Script file.
* // Interface script file.
* var webEntity = Entities.addEntity({
* type: "Web",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -3 })),
@ -525,9 +533,12 @@ public slots:
Q_INVOKABLE bool isAddedEntity(const QUuid& id);
/**jsdoc
* Calculates the size of some text in a text entity.
* Calculates the size of some text in a {@link Entities.EntityProperties-Text|Text} entity. The entity need not be set
* visible.
* <p><strong>Note:</strong> The size of text in a Text entity cannot be calculated immediately after the
* entity is created; a short delay is required while the entity finishes being created.</p>
* @function Entities.textSize
* @param {Uuid} id - The ID of the entity to use for calculation.
* @param {Uuid} id - The ID of the Text entity to use for calculation.
* @param {string} text - The string to calculate the size of.
* @returns {Size} The size of the <code>text</code> in meters if the object is a text entity, otherwise
* <code>{ height: 0, width : 0 }</code>.
@ -1794,7 +1805,7 @@ public slots:
* <title>HELLO</title>
* </head>
* <body>
* <h1>HELLO</h1></h1>
* <h1>HELLO</h1>
* <script>
* function onScriptEventReceived(message) {
* // Message received from the script.

View file

@ -30,8 +30,8 @@ namespace entity {
* </thead>
* <tbody>
* <tr><td><code>"Circle"</code></td><td>2D</td><td>A circle oriented in 3D.</td></tr>
* <tr><td><code>"Cube"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cone"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cube"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cylinder"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Dodecahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Hexagon"</code></td><td>3D</td><td>A hexagonal prism.</td></tr>

View file

@ -40,6 +40,8 @@ const Element Element::COLOR_COMPRESSED_EAC_RED_SIGNED { TILE4x4, COMPRESSED, CO
const Element Element::COLOR_COMPRESSED_EAC_XY { TILE4x4, COMPRESSED, COMPRESSED_EAC_XY };
const Element Element::COLOR_COMPRESSED_EAC_XY_SIGNED { TILE4x4, COMPRESSED, COMPRESSED_EAC_XY_SIGNED };
const Element Element::DEPTH24_STENCIL8 { SCALAR, UINT32, DEPTH_STENCIL };
const Element Element::VEC2NU8_XY{ VEC2, NUINT8, XY };
const Element Element::COLOR_R11G11B10{ SCALAR, FLOAT, R11G11B10 };

View file

@ -358,6 +358,7 @@ public:
static const Element COLOR_COMPRESSED_EAC_RED_SIGNED;
static const Element COLOR_COMPRESSED_EAC_XY;
static const Element COLOR_COMPRESSED_EAC_XY_SIGNED;
static const Element DEPTH24_STENCIL8;
static const Element VEC2NU8_XY;
static const Element VEC4F_COLOR_RGBA;
static const Element VEC2F_UV;

View file

@ -30,7 +30,7 @@
#include "UserActivityLogger.h"
#include "udt/PacketHeaders.h"
const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome";
const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json";
const QString DEFAULT_HOME_ADDRESS = "file:///~/serverless/tutorial.json";
const QString REDIRECT_HIFI_ADDRESS = "file:///~/serverless/redirect.json";
const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager";

View file

@ -384,6 +384,8 @@ static const char* stateToStr(CharacterController::State state) {
return "InAir";
case CharacterController::State::Hover:
return "Hover";
case CharacterController::State::Seated:
return "Seated";
default:
return "Unknown";
}
@ -739,9 +741,11 @@ void CharacterController::updateState() {
// disable normal state transitions while collisionless
const btScalar MAX_WALKING_SPEED = 2.65f;
if (collisionMask == BULLET_COLLISION_MASK_COLLISIONLESS) {
// when collisionless: only switch between State::Ground and State::Hover
// when collisionless: only switch between State::Ground, State::Hover and State::Seated
// and bypass state debugging
if (rayHasHit) {
if (_isSeated) {
_state = State::Seated;
} else if (rayHasHit) {
if (velocity.length() > (MAX_WALKING_SPEED)) {
_state = State::Hover;
} else {
@ -802,7 +806,7 @@ void CharacterController::updateState() {
}
break;
}
case State::Hover:
case State::Hover: {
btScalar horizontalSpeed = (velocity - velocity.dot(_currentUp) * _currentUp).length();
bool flyingFast = horizontalSpeed > (MAX_WALKING_SPEED * 0.75f);
if (!_zoneFlyingAllowed) {
@ -815,6 +819,11 @@ void CharacterController::updateState() {
SET_STATE(State::Ground, "touching ground");
}
break;
}
case State::Seated: {
SET_STATE(State::Ground, "Standing up");
break;
}
}
}
}

View file

@ -111,7 +111,8 @@ public:
Ground = 0,
Takeoff,
InAir,
Hover
Hover,
Seated
};
State getState() const { return _state; }
@ -135,6 +136,8 @@ public:
void setCollisionlessAllowed(bool value);
void setPendingFlagsUpdateCollisionMask(){ _pendingFlags |= PENDING_FLAG_UPDATE_COLLISION_MASK; }
void setSeated(bool isSeated) { _isSeated = isSeated; }
bool getSeated() { return _isSeated; }
protected:
#ifdef DEBUG_STATE_CHANGE
@ -208,6 +211,7 @@ protected:
State _state;
bool _isPushingUp;
bool _isStuck { false };
bool _isSeated { false };
btDynamicsWorld* _dynamicsWorld { nullptr };
btRigidBody* _rigidBody { nullptr };

View file

@ -97,8 +97,8 @@ bool filterOnProcessors(const platform::json& computer, const platform::json& cp
// intel integrated graphics
if (gpuVendor.find(keys::gpu::vendor_Intel) != std::string::npos) {
// go mid because GPU
tier = Profiler::Tier::MID;
// go LOW because Intel GPU
tier = Profiler::Tier::LOW;
return true;
}
// AMD gpu

View file

@ -107,7 +107,8 @@ void Instance::enumerateNics() {
json Instance::getCPU(int index) {
assert(index <(int) _cpus.size());
if (index >= (int)_cpus.size())
if (index < 0 || (int) _cpus.size() <= index)
return json();
return _cpus.at(index);
@ -116,7 +117,7 @@ json Instance::getCPU(int index) {
json Instance::getGPU(int index) {
assert(index <(int) _gpus.size());
if (index >=(int) _gpus.size())
if (index < 0 || (int) _gpus.size() <= index)
return json();
return _gpus.at(index);
@ -126,7 +127,7 @@ json Instance::getGPU(int index) {
json Instance::getDisplay(int index) {
assert(index <(int) _displays.size());
if (index >=(int) _displays.size())
if (index < 0 || (int) _displays.size() <= index)
return json();
return _displays.at(index);

View file

@ -31,7 +31,7 @@
* <tr><td>INTERSECTED_ENTITY</td><td><code>1</code></td><td>Intersected an entity.</td></tr>
* <tr><td>INTERSECTED_LOCAL_ENTITY</td><td><code>2</code></td><td>Intersected a local entity.</td></tr>
* <tr><td>INTERSECTED_AVATAR</td><td><code>3</code></td><td>Intersected an avatar.</td></tr>
* <tr><td>INTERSECTED_HUD</td><td><code>4</code></td><td>Intersected the HUD sphere.</td></tr>
* <tr><td>INTERSECTED_HUD</td><td><code>4</code></td><td>Intersected the HUD surface.</td></tr>
* </tbody>
* </table>
* @typedef {number} IntersectionType

View file

@ -44,10 +44,10 @@ using namespace render;
static void loadLightProgram(int programId, bool lightVolume, gpu::PipelinePointer& program);
void DeferredLightingEffect::init() {
loadLightProgram(shader::render_utils::program::directional_ambient_light, false, _directionalAmbientSphereLight);
loadLightProgram(shader::render_utils::program::directional_skybox_light_ambient, false, _directionalAmbientSphereLight);
loadLightProgram(shader::render_utils::program::directional_skybox_light, false, _directionalSkyboxLight);
loadLightProgram(shader::render_utils::program::directional_ambient_light_shadow, false, _directionalAmbientSphereLightShadow);
loadLightProgram(shader::render_utils::program::directional_skybox_light_ambient_shadow, false, _directionalAmbientSphereLightShadow);
loadLightProgram(shader::render_utils::program::directional_skybox_light_shadow, false, _directionalSkyboxLightShadow);
loadLightProgram(shader::render_utils::program::local_lights_shading, true, _localLight);

View file

@ -38,7 +38,7 @@ void FramebufferCache::createPrimaryFramebuffer() {
gpu::FramebufferPointer FramebufferCache::getFramebuffer() {
std::unique_lock<std::mutex> lock(_mutex);
if (_cachedFramebuffers.empty()) {
_cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create("cached", gpu::Element::COLOR_SRGBA_32, _frameBufferSize.width(), _frameBufferSize.height())));
_cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create("cached", gpu::Element::COLOR_SRGBA_32, gpu::Element::DEPTH24_STENCIL8, _frameBufferSize.width(), _frameBufferSize.height())));
}
gpu::FramebufferPointer result = _cachedFramebuffers.front();
_cachedFramebuffers.pop_front();

View file

@ -1,57 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// directional_ambient_light.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/3/14.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferRead.slh@>
<@include render-utils/ShaderConstants.h@>
<@include GlobalLight.slh@>
<$declareEvalAmbientSphereGlobalColor(supportScattering)$>
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
#define _texCoord1 _texCoord01.zw
layout(location=0) out vec4 _fragColor;
void main(void) {
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
float shadowAttenuation = 1.0;
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
discard;
} else {
vec4 midNormalCurvature = vec4(0);
vec4 lowNormalCurvature = vec4(0);
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
float check = float(frag.mode == FRAG_MODE_SCATTERING);
midNormalCurvature = check * midNormalCurvature;
lowNormalCurvature = check * lowNormalCurvature;
vec3 color = evalAmbientSphereGlobalColor(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.albedo,
frag.fresnel,
frag.metallic,
frag.roughness,
frag.scattering,
midNormalCurvature,
lowNormalCurvature);
_fragColor = vec4(color, 1.0);
}
}

View file

@ -1,63 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// directional_ambient_light_shadow.frag
// fragment shader
//
// Created by Zach Pomerantz on 1/18/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferRead.slh@>
<@include render-utils/ShaderConstants.h@>
<@include GlobalLight.slh@>
<$declareEvalAmbientSphereGlobalColor(isScattering)$>
<@include Shadow.slh@>
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
#define _texCoord1 _texCoord01.zw
layout(location=0) out vec4 _fragColor;
void main(void) {
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
vec4 viewPos = vec4(frag.position.xyz, 1.0);
vec4 worldPos = getViewInverse() * viewPos;
Light shadowLight = getKeyLight();
vec3 worldLightDirection = getLightDirection(shadowLight);
float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal);
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
discard;
} else {
vec4 midNormalCurvature = vec4(0);
vec4 lowNormalCurvature = vec4(0);
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
float check = float(frag.mode == FRAG_MODE_SCATTERING);
midNormalCurvature = check * midNormalCurvature;
lowNormalCurvature = check * lowNormalCurvature;
vec3 color = evalAmbientSphereGlobalColor(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.albedo,
frag.fresnel,
frag.metallic,
frag.roughness,
frag.scattering,
midNormalCurvature,
lowNormalCurvature);
_fragColor = vec4(color, 1.0);
}
}

View file

@ -1,10 +1,8 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// <$_SCRIBE_FILENAME$>
// Generated on <$_SCRIBE_DATE$>
//
// directional_skybox_light.frag
// fragment shader
//
// Created by Sam Gateau on 5/8/2015.
// Copyright 2016 High Fidelity, Inc.
//
@ -15,20 +13,36 @@
<@include render-utils/ShaderConstants.h@>
<@include GlobalLight.slh@>
<$declareEvalSkyboxGlobalColor(isScattering, _SCRIBE_NULL)$>
<@if HIFI_USE_AMBIENT@>
<$declareEvalAmbientSphereGlobalColor(supportScattering)$>
<@else@>
<$declareEvalSkyboxGlobalColor(supportScattering, _SCRIBE_NULL)$>
<@endif@>
<@if HIFI_USE_SHADOW@>
<@include Shadow.slh@>
<@endif@>
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
#define _texCoord1 _texCoord01.zw
layout(location=0) out vec4 _fragColor;
void main(void) {
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
<@if HIFI_USE_SHADOW@>
vec4 viewPos = vec4(frag.position.xyz, 1.0);
vec4 worldPos = getViewInverse() * viewPos;
Light shadowLight = getKeyLight();
vec3 worldLightDirection = getLightDirection(shadowLight);
float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal);
<@else@>
float shadowAttenuation = 1.0;
<@endif@>
// Light mapped or not ?
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
discard;
} else {
@ -39,6 +53,21 @@ void main(void) {
midNormalCurvature = check * midNormalCurvature;
lowNormalCurvature = check * lowNormalCurvature;
<@if HIFI_USE_AMBIENT@>
vec3 color = evalAmbientSphereGlobalColor(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.albedo,
frag.fresnel,
frag.metallic,
frag.roughness,
frag.scattering,
midNormalCurvature,
lowNormalCurvature);
<@else@>
vec3 color = evalSkyboxGlobalColor(
getViewInverse(),
shadowAttenuation,
@ -52,6 +81,7 @@ void main(void) {
frag.scattering,
midNormalCurvature,
lowNormalCurvature);
<@endif@>
_fragColor = vec4(color, 1.0);
}

View file

@ -1,64 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// directional_skybox_light_shadow.frag
// fragment shader
//
// Created by Zach Pomerantz on 1/18/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//!>
<@include DeferredBufferRead.slh@>
<@include render-utils/ShaderConstants.h@>
<@include GlobalLight.slh@>
<$declareEvalSkyboxGlobalColor(isScattering, _SCRIBE_NULL)$>
<@include Shadow.slh@>
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
#define _texCoord1 _texCoord01.zw
layout(location=0) out vec4 _fragColor;
void main(void) {
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
vec4 viewPos = vec4(frag.position.xyz, 1.0);
vec4 worldPos = getViewInverse() * viewPos;
Light shadowLight = getKeyLight();
vec3 worldLightDirection = getLightDirection(shadowLight);
float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal);
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
discard;
} else {
vec4 midNormalCurvature = vec4(0);
vec4 lowNormalCurvature = vec4(0);
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
float check = float(frag.mode == FRAG_MODE_SCATTERING);
midNormalCurvature = check * midNormalCurvature;
lowNormalCurvature = check * lowNormalCurvature;
vec3 color = evalSkyboxGlobalColor(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.albedo,
frag.fresnel,
frag.metallic,
frag.roughness,
frag.scattering,
midNormalCurvature,
lowNormalCurvature);
_fragColor = vec4(color, 1.0);
}
}

View file

@ -1 +0,0 @@
VERTEX deferred_light

View file

@ -1 +1,2 @@
VERTEX deferred_light
DEFINES ambient:f shadow:f

View file

@ -1 +0,0 @@
VERTEX deferred_light

View file

@ -33,5 +33,9 @@ ScriptAudioInjector::ScriptAudioInjector(const AudioInjectorPointer& injector) :
}
ScriptAudioInjector::~ScriptAudioInjector() {
DependencyManager::get<AudioInjectorManager>()->stop(_injector);
}
const auto audioInjectorManager = DependencyManager::get<AudioInjectorManager>();
// AudioInjectorManager may have been destroyed on application shutdown.
if (audioInjectorManager) {
audioInjectorManager->stop(_injector);
}
}

View file

@ -106,4 +106,13 @@ static const float AVATAR_WALK_SPEED_SCALAR = 1.0f;
static const float AVATAR_DESKTOP_SPRINT_SPEED_SCALAR = 3.0f;
static const float AVATAR_HMD_SPRINT_SPEED_SCALAR = 2.0f;
enum AvatarReaction {
AVATAR_REACTION_POSITIVE = 0,
AVATAR_REACTION_NEGATIVE,
AVATAR_REACTION_RAISE_HAND,
AVATAR_REACTION_APPLAUD,
AVATAR_REACTION_POINT,
NUM_AVATAR_REACTIONS
};
#endif // hifi_AvatarConstants_h

View file

@ -82,39 +82,22 @@ std::vector<CPUIdent::Feature> CPUIdent::getAllFeatures() {
};
CPUIdent::CPUIdent_Internal::CPUIdent_Internal()
: nIds_{ 0 },
nExIds_{ 0 },
isIntel_{ false },
isAMD_{ false },
f_1_ECX_{ 0 },
f_1_EDX_{ 0 },
f_7_EBX_{ 0 },
f_7_ECX_{ 0 },
f_81_ECX_{ 0 },
f_81_EDX_{ 0 },
data_{},
extdata_{}
{
CPUIdent::CPUIdent_Internal::CPUIdent_Internal() {
//int cpuInfo[4] = {-1};
std::array<uint32_t, 4> cpui;
uint32_t cpui[4];
// Calling __cpuid with 0x0 as the function_id argument
// gets the number of the highest valid function ID.
getCPUID(cpui.data(), 0);
getCPUID(cpui, 0);
nIds_ = cpui[0];
for (uint32_t i = 0; i <= nIds_; ++i) {
getCPUIDEX(cpui.data(), i, 0);
data_.push_back(cpui);
}
// Capture vendor string
char vendor[0x20];
memset(vendor, 0, sizeof(vendor));
*reinterpret_cast<int*>(vendor) = data_[0][1];
*reinterpret_cast<int*>(vendor + 4) = data_[0][3];
*reinterpret_cast<int*>(vendor + 8) = data_[0][2];
getCPUIDEX(cpui, 0, 0);
*reinterpret_cast<int*>(vendor) = cpui[1];
*reinterpret_cast<int*>(vendor + 4) = cpui[3];
*reinterpret_cast<int*>(vendor + 8) = cpui[2];
vendor_ = vendor;
if (vendor_ == "GenuineIntel") {
isIntel_ = true;
@ -125,40 +108,41 @@ CPUIdent::CPUIdent_Internal::CPUIdent_Internal()
// load bitset with flags for function 0x00000001
if (nIds_ >= 1) {
f_1_ECX_ = data_[1][2];
f_1_EDX_ = data_[1][3];
getCPUIDEX(cpui, 1, 0);
f_1_ECX_ = cpui[2];
f_1_EDX_ = cpui[3];
}
// load bitset with flags for function 0x00000007
if (nIds_ >= 7) {
f_7_EBX_ = data_[7][1];
f_7_ECX_ = data_[7][2];
getCPUIDEX(cpui, 7, 0);
f_7_EBX_ = cpui[1];
f_7_ECX_ = cpui[2];
}
// Calling __cpuid with 0x80000000 as the function_id argument
// gets the number of the highest valid extended ID.
getCPUID(cpui.data(), 0x80000000);
getCPUID(cpui, 0x80000000);
nExIds_ = cpui[0];
char brand[0x40];
memset(brand, 0, sizeof(brand));
for (uint32_t i = 0x80000000; i <= nExIds_; ++i) {
getCPUIDEX(cpui.data(), i, 0);
extdata_.push_back(cpui);
}
// load bitset with flags for function 0x80000001
if (nExIds_ >= 0x80000001) {
f_81_ECX_ = extdata_[1][2];
f_81_EDX_ = extdata_[1][3];
getCPUIDEX(cpui, 0x80000001, 0);
f_81_ECX_ = cpui[2];
f_81_EDX_ = cpui[3];
}
// Interpret CPU brand string if reported
if (nExIds_ >= 0x80000004) {
memcpy(brand, extdata_[2].data(), sizeof(cpui));
memcpy(brand + 16, extdata_[3].data(), sizeof(cpui));
memcpy(brand + 32, extdata_[4].data(), sizeof(cpui));
getCPUIDEX(cpui, 0x80000002, 0);
memcpy(brand, cpui, sizeof(cpui));
getCPUIDEX(cpui, 0x80000003, 0);
memcpy(brand + 16, cpui, sizeof(cpui));
getCPUIDEX(cpui, 0x80000004, 0);
memcpy(brand + 32, cpui, sizeof(cpui));
brand_ = brand;
}
}

View file

@ -100,25 +100,22 @@ public:
private:
static const CPUIdent_Internal CPU_Rep;
class CPUIdent_Internal
{
class CPUIdent_Internal {
public:
CPUIdent_Internal();
uint32_t nIds_;
uint32_t nExIds_;
uint32_t nIds_{ 0 };
uint32_t nExIds_{ 0 };
std::string vendor_;
std::string brand_;
bool isIntel_;
bool isAMD_;
std::bitset<32> f_1_ECX_;
std::bitset<32> f_1_EDX_;
std::bitset<32> f_7_EBX_;
std::bitset<32> f_7_ECX_;
std::bitset<32> f_81_ECX_;
std::bitset<32> f_81_EDX_;
std::vector<std::array<uint32_t, 4>> data_;
std::vector<std::array<uint32_t, 4>> extdata_;
bool isIntel_{ false };
bool isAMD_{ false };
std::bitset<32> f_1_ECX_{ 0 };
std::bitset<32> f_1_EDX_{ 0 };
std::bitset<32> f_7_EBX_{ 0 };
std::bitset<32> f_7_ECX_{ 0 };
std::bitset<32> f_81_ECX_{ 0 };
std::bitset<32> f_81_EDX_{ 0 };
};
};

View file

@ -26,7 +26,7 @@ public:
* <tr><td>PICK_AVATAR_ENTITIES</td><td><code>2</code></td><td>Include avatar entities when intersecting.</td></tr>
* <tr><td>PICK_LOCAL_ENTITIES</td><td><code>4</code></td><td>Include local entities when intersecting.</td></tr>
* <tr><td>PICK_AVATATRS</td><td><code>8</code></td><td>Include avatars when intersecting.</td></tr>
* <tr><td>PICK_HUD</td><td><code>16</code></td><td>Include the HUD sphere when intersecting in HMD mode.</td></tr>
* <tr><td>PICK_HUD</td><td><code>16</code></td><td>Include the HUD surface when intersecting in HMD mode.</td></tr>
* <tr><td>PICK_INCLUDE_VISIBLE</td><td><code>32</code></td><td>Include visible objects when intersecting.</td></tr>
* <tr><td>PICK_INCLUDE_INVISIBLE</td><td><code>64</code></td><td>Include invisible objects when intersecting.</td></tr>
* <tr><td>PICK_INCLUDE_COLLIDABLE</td><td><code>128</code></td><td>Include collidable objects when

View file

@ -19,8 +19,8 @@
* </thead>
* <tbody>
* <tr><td><code>"world"</code></td><td>The entity is drawn in the world with everything else.</td></tr>
* <tr><td><code>"front"</code></td><td>The entity is drawn on top of the world layer but behind the HUD sphere.</td></tr>
* <tr><td><code>"hud"</code></td><td>The entity is drawn on top of other layers and the HUD sphere.</td></tr>
* <tr><td><code>"front"</code></td><td>The entity is drawn on top of the world layer but behind the HUD surface.</td></tr>
* <tr><td><code>"hud"</code></td><td>The entity is drawn on top of other layers and the HUD surface.</td></tr>
* </tbody>
* </table>
* @typedef {string} Entities.RenderLayer

View file

@ -59,6 +59,7 @@ var DISTANCE_SCALER_ALWAYS_ON = 0.45;
var distanceScaler = DISTANCE_SCALER_ON;
var userScaler = 1.0;
var DEFAULT_LINE_HEIGHT = entityProps.lineHeight;
var ADDITIONAL_PADDING = 1.06;
function calculateInitialProperties(uuid) {
var adjustedScaler = null;
var distance = null;
@ -82,7 +83,7 @@ function calculateInitialProperties(uuid) {
distanceScaler = avatarNametagMode === "on" ? DISTANCE_SCALER_ON : DISTANCE_SCALER_ALWAYS_ON;
adjustedScaler = distance * distanceScaler;
// Get the new dimensions from the text helper
dimensions = [textHelper.getTotalTextLength(), DEFAULT_LINE_HEIGHT, Z_SIZE];
dimensions = [textHelper.getTotalTextLength() * ADDITIONAL_PADDING, DEFAULT_LINE_HEIGHT, Z_SIZE];
// Adjust the dimensions by the modified distance scaler
scaledDimensions = Vec3.multiply(dimensions, adjustedScaler);

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