mirror of
https://github.com/lubosz/overte.git
synced 2025-04-26 22:56:02 +02:00
Merge branch 'hifi-master' into kpi-v1-modkit-rc
This commit is contained in:
commit
058c81aa1a
172 changed files with 7742 additions and 1903 deletions
BUILD_WIN.mdCMakeLists.txtREADME.md
assignment-client/src
cmake/macros
interface
resources
avatar
animations
emote_agree_acknowledge.fbxemote_clap01_all.fbxemote_disagree_defeated.fbxemote_point01_all.fbxemote_raisehand01_all.fbxteleport.fbx
avatar-animation.jsonhtml
qml
serverless
src
Application.cppApplication.hAvatarBookmarks.cppAvatarBookmarks.hBookmarks.hLocationBookmarks.hMacHelper.cppMacHelper.hMenu.cppPerformanceManager.cppVisionSqueeze.cppVisionSqueeze.h
avatar
octree
raypick
scripting
Audio.hDesktopScriptingInterface.cppDesktopScriptingInterface.hHMDScriptingInterface.cppHMDScriptingInterface.hPlatformInfoScriptingInterface.cppPlatformInfoScriptingInterface.hWindowScriptingInterface.h
ui
launchers
libraries
animation/src
avatars/src
display-plugins/src/display-plugins
AbstractHMDScriptingInterface.cppCompositorHelper.hDrawTextureWithVisionSqueeze.slfDrawTextureWithVisionSqueeze.slpOpenGLDisplayPlugin.cppOpenGLDisplayPlugin.hVisionSqueeze.slh
hmd
entities-renderer/src
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
=========
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
BIN
interface/resources/avatar/animations/emote_clap01_all.fbx
Normal file
BIN
interface/resources/avatar/animations/emote_clap01_all.fbx
Normal file
Binary file not shown.
Binary file not shown.
BIN
interface/resources/avatar/animations/emote_point01_all.fbx
Normal file
BIN
interface/resources/avatar/animations/emote_point01_all.fbx
Normal file
Binary file not shown.
BIN
interface/resources/avatar/animations/emote_raisehand01_all.fbx
Normal file
BIN
interface/resources/avatar/animations/emote_raisehand01_all.fbx
Normal file
Binary file not shown.
BIN
interface/resources/avatar/animations/teleport.fbx
Normal file
BIN
interface/resources/avatar/animations/teleport.fbx
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -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.
|
||||
|
|
|
@ -30,7 +30,6 @@ Windows.Window {
|
|||
|
||||
signal selfDestruct();
|
||||
|
||||
property var flags: 0;
|
||||
property var additionalFlags: 0;
|
||||
property var overrideFlags: 0;
|
||||
|
||||
|
@ -158,8 +157,7 @@ Windows.Window {
|
|||
if (Qt.platform.os !== "windows" && (root.additionalFlags & Desktop.ALWAYS_ON_TOP)) {
|
||||
nativeWindowFlags |= Qt.WindowStaysOnTopHint;
|
||||
}
|
||||
root.flags = root.overrideFlags || nativeWindowFlags;
|
||||
nativeWindow.flags = root.flags;
|
||||
nativeWindow.flags = root.overrideFlags || nativeWindowFlags;
|
||||
|
||||
nativeWindow.x = interactiveWindowPosition.x;
|
||||
nativeWindow.y = interactiveWindowPosition.y;
|
||||
|
@ -317,7 +315,7 @@ Windows.Window {
|
|||
// set invisible on close, to make it not re-appear unintended after switching PresentationMode
|
||||
interactiveWindowVisible = false;
|
||||
|
||||
if ((root.flags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) {
|
||||
if ((root.additionalFlags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) {
|
||||
selfDestruct();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,6 @@ Text {
|
|||
style: Text.Outline;
|
||||
styleColor: "black";
|
||||
font.pixelSize: 12;
|
||||
font.bold: true;
|
||||
font.family: "monospace";
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ FocusScope {
|
|||
property alias editable: comboBox.editable
|
||||
property alias comboBox: comboBox
|
||||
readonly property alias currentText: comboBox.currentText;
|
||||
property alias displayText: comboBox.displayText;
|
||||
property alias currentIndex: comboBox.currentIndex;
|
||||
property int currentHighLightedIndex: comboBox.currentIndex;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
//
|
||||
// GraphicsSettings.qml
|
||||
// qml\hifi\dialogs\graphics
|
||||
//
|
||||
// Created by Zach Fox on 2019-07-10
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.12
|
||||
import stylesUit 1.0 as HifiStylesUit
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
import "qrc:////qml//controls" as HifiControls
|
||||
import PerformanceEnums 1.0
|
||||
|
||||
Item {
|
||||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
id: graphicsSettingsColumnLayout
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 26
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 26
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: HMD.active ? 80 : 0
|
||||
spacing: 8
|
||||
|
||||
ColumnLayout {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.topMargin: 18
|
||||
spacing: 0
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
text: "GRAPHICS SETTINGS"
|
||||
Layout.maximumWidth: parent.width
|
||||
height: 30
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 10
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceLow
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Low"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.LOW
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.LOW);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceMedium
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Medium"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.MID
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.MID);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceHigh
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "High"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.HIGH
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.HIGH);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceCustom
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Custom"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.UNKNOWN
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 10
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: worldDetailHeader
|
||||
text: "World Detail"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: worldDetailModel
|
||||
|
||||
ListElement {
|
||||
text: "Low World Detail"
|
||||
worldDetailQualityValue: 0.25
|
||||
}
|
||||
ListElement {
|
||||
text: "Medium World Detail"
|
||||
worldDetailQualityValue: 0.5
|
||||
}
|
||||
ListElement {
|
||||
text: "Full World Detail"
|
||||
worldDetailQualityValue: 0.75
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: worldDetailDropdown
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: worldDetailHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: worldDetailModel
|
||||
currentIndex: -1
|
||||
|
||||
function refreshWorldDetailDropdown() {
|
||||
var currentWorldDetailQuality = LODManager.worldDetailQuality;
|
||||
if (currentWorldDetailQuality <= 0.25) {
|
||||
worldDetailDropdown.currentIndex = 0;
|
||||
} else if (currentWorldDetailQuality <= 0.5) {
|
||||
worldDetailDropdown.currentIndex = 1;
|
||||
} else {
|
||||
worldDetailDropdown.currentIndex = 2;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
worldDetailDropdown.refreshWorldDetailDropdown();
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
LODManager.worldDetailQuality = model.get(currentIndex).worldDetailQualityValue;
|
||||
worldDetailDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 20
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: renderingEffectsHeader
|
||||
text: "Rendering Effects"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: renderingEffectsModel
|
||||
|
||||
ListElement {
|
||||
text: "No Rendering Effects"
|
||||
preferredRenderMethod: 1 // "FORWARD"
|
||||
shadowsEnabled: false
|
||||
}
|
||||
ListElement {
|
||||
text: "Local Lights, Fog, Bloom"
|
||||
preferredRenderMethod: 0 // "DEFERRED"
|
||||
shadowsEnabled: false
|
||||
}
|
||||
ListElement {
|
||||
text: "Local Lights, Fog, Bloom, Shadows"
|
||||
preferredRenderMethod: 0 // "DEFERRED"
|
||||
shadowsEnabled: true
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: renderingEffectsDropdown
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: renderingEffectsHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: renderingEffectsModel
|
||||
currentIndex: -1
|
||||
|
||||
function refreshRenderingEffectsDropdownDisplay() {
|
||||
if (Render.shadowsEnabled) {
|
||||
renderingEffectsDropdown.currentIndex = 2;
|
||||
} else if (Render.renderMethod === 0) {
|
||||
renderingEffectsDropdown.currentIndex = 1;
|
||||
} else {
|
||||
renderingEffectsDropdown.currentIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
renderingEffectsDropdown.refreshRenderingEffectsDropdownDisplay();
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
var renderMethodToSet = 1;
|
||||
if (model.get(currentIndex).preferredRenderMethod === 0 &&
|
||||
PlatformInfo.isRenderMethodDeferredCapable()) {
|
||||
renderMethodToSet = 0;
|
||||
}
|
||||
Render.renderMethod = renderMethodToSet;
|
||||
Render.shadowsEnabled = model.get(currentIndex).shadowsEnabled;
|
||||
renderingEffectsDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 20
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: refreshRateHeader
|
||||
text: "Refresh Rate"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: refreshRateModel
|
||||
|
||||
ListElement {
|
||||
text: "Economical"
|
||||
refreshRatePreset: 0 // RefreshRateProfile::ECO
|
||||
}
|
||||
ListElement {
|
||||
text: "Interactive"
|
||||
refreshRatePreset: 1 // RefreshRateProfile::INTERACTIVE
|
||||
}
|
||||
ListElement {
|
||||
text: "Real-Time"
|
||||
refreshRatePreset: 2 // RefreshRateProfile::REALTIME
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: refreshRateDropdown
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: refreshRateHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: refreshRateModel
|
||||
currentIndex: -1
|
||||
|
||||
function refreshRefreshRateDropdownDisplay() {
|
||||
if (Performance.getRefreshRateProfile() === 0) {
|
||||
refreshRateDropdown.currentIndex = 0;
|
||||
} else if (Performance.getRefreshRateProfile() === 1) {
|
||||
refreshRateDropdown.currentIndex = 1;
|
||||
} else {
|
||||
refreshRateDropdown.currentIndex = 2;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
refreshRateDropdown.refreshRefreshRateDropdownDisplay();
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
Performance.setRefreshRateProfile(model.get(currentIndex).refreshRatePreset);
|
||||
refreshRateDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 16
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: resolutionHeader
|
||||
text: "Resolution Scale (" + Number.parseFloat(Render.viewportResolutionScale).toPrecision(3) + ")"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: resolutionScaleSlider
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: resolutionHeader.right
|
||||
anchors.leftMargin: 57
|
||||
anchors.top: parent.top
|
||||
width: 150
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
minimumValue: 0.25
|
||||
maximumValue: 1.0
|
||||
stepSize: 0.02
|
||||
value: Render.viewportResolutionScale
|
||||
live: true
|
||||
|
||||
function updateResolutionScale(sliderValue) {
|
||||
if (Render.viewportResolutionScale !== sliderValue) {
|
||||
Render.viewportResolutionScale = sliderValue;
|
||||
}
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
updateResolutionScale(value);
|
||||
}
|
||||
onPressedChanged: {
|
||||
if (!pressed) {
|
||||
updateResolutionScale(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshAllDropdowns() {
|
||||
worldDetailDropdown.refreshWorldDetailDropdown();
|
||||
renderingEffectsDropdown.refreshRenderingEffectsDropdownDisplay();
|
||||
refreshRateDropdown.refreshRefreshRateDropdownDisplay();
|
||||
}
|
||||
}
|
|
@ -91,7 +91,7 @@ Item {
|
|||
|
||||
SimplifiedControls.TextField {
|
||||
id: myDisplayNameText
|
||||
text: MyAvatar.sessionDisplayName === "" ? MyAvatar.displayName : MyAvatar.sessionDisplayName
|
||||
text: MyAvatar.displayName
|
||||
maximumLength: 256
|
||||
clip: true
|
||||
selectByMouse: true
|
||||
|
|
|
@ -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
|
@ -257,6 +257,10 @@ extern "C" {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "MacHelper.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <android/log.h>
|
||||
#include "AndroidHelper.h"
|
||||
|
@ -960,6 +964,9 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<KeyboardScriptingInterface>();
|
||||
DependencyManager::set<GrabManager>();
|
||||
DependencyManager::set<AvatarPackager>();
|
||||
#ifdef Q_OS_MAC
|
||||
DependencyManager::set<MacHelper>();
|
||||
#endif
|
||||
|
||||
QString setBookmarkValue = getCmdOption(argc, constArgv, "--setBookmark");
|
||||
if (!setBookmarkValue.isEmpty()) {
|
||||
|
@ -2810,13 +2817,14 @@ void Application::cleanupBeforeQuit() {
|
|||
DependencyManager::destroy<TabletScriptingInterface>();
|
||||
DependencyManager::destroy<ToolbarScriptingInterface>();
|
||||
DependencyManager::destroy<OffscreenUi>();
|
||||
|
||||
|
||||
DependencyManager::destroy<OffscreenQmlSurfaceCache>();
|
||||
|
||||
_snapshotSoundInjector = nullptr;
|
||||
|
||||
// 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>();
|
||||
|
||||
|
@ -2856,6 +2864,9 @@ Application::~Application() {
|
|||
_gameWorkload.shutdown();
|
||||
|
||||
DependencyManager::destroy<Preferences>();
|
||||
#ifdef Q_OS_MAC
|
||||
DependencyManager::destroy<MacHelper>();
|
||||
#endif
|
||||
|
||||
_entityClipboard->eraseAllOctreeElements();
|
||||
_entityClipboard.reset();
|
||||
|
@ -5976,6 +5987,7 @@ void Application::resetPhysicsReadyInformation() {
|
|||
_gpuTextureMemSizeStabilityCount = 0;
|
||||
_gpuTextureMemSizeAtLastCheck = 0;
|
||||
_physicsEnabled = false;
|
||||
_octreeProcessor.stopSafeLanding();
|
||||
}
|
||||
|
||||
void Application::reloadResourceCaches() {
|
||||
|
@ -6235,6 +6247,7 @@ void Application::tryToEnablePhysics() {
|
|||
// We keep physics disabled until we've received a full scene and everything near the avatar in that
|
||||
// scene is ready to compute its collision shape.
|
||||
if (getMyAvatar()->isReadyForPhysics()) {
|
||||
_octreeProcessor.resetSafeLanding();
|
||||
_physicsEnabled = true;
|
||||
setIsInterstitialMode(false);
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
|
@ -6758,6 +6771,12 @@ void Application::update(float deltaTime) {
|
|||
if (!getActiveDisplayPlugin()->isActive()) {
|
||||
getMain3DScene()->processTransactionQueue();
|
||||
}
|
||||
|
||||
// decide if the sensorToWorldMatrix is changing in a way that warrents squeezing the edges of the view down
|
||||
if (getActiveDisplayPlugin()->isHmd()) {
|
||||
PerformanceTimer perfTimer("squeezeVision");
|
||||
_visionSqueeze.updateVisionSqueeze(myAvatar->getSensorToWorldMatrix(), deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateRenderArgs(float deltaTime) {
|
||||
|
@ -6964,13 +6983,16 @@ int Application::sendNackPackets() {
|
|||
}
|
||||
|
||||
void Application::queryOctree(NodeType_t serverType, PacketType packetType) {
|
||||
|
||||
if (!_settingsLoaded) {
|
||||
return; // bail early if settings are not loaded
|
||||
}
|
||||
|
||||
const bool isModifiedQuery = !_physicsEnabled;
|
||||
if (isModifiedQuery) {
|
||||
if (!_octreeProcessor.safeLandingIsActive()) {
|
||||
// don't send the octreeQuery until SafeLanding knows it has started
|
||||
return;
|
||||
}
|
||||
// Create modified view that is a simple sphere.
|
||||
bool interstitialModeEnabled = DependencyManager::get<NodeList>()->getDomainHandler().getInterstitialModeEnabled();
|
||||
|
||||
|
@ -7193,7 +7215,6 @@ void Application::clearDomainOctreeDetails(bool clearAll) {
|
|||
|
||||
void Application::domainURLChanged(QUrl domainURL) {
|
||||
// disable physics until we have enough information about our new location to not cause craziness.
|
||||
resetPhysicsReadyInformation();
|
||||
setIsServerlessMode(domainURL.scheme() != URL_SCHEME_HIFI);
|
||||
if (isServerlessMode()) {
|
||||
loadServerlessDomain(domainURL);
|
||||
|
@ -7203,7 +7224,6 @@ void Application::domainURLChanged(QUrl domainURL) {
|
|||
|
||||
void Application::goToErrorDomainURL(QUrl errorDomainURL) {
|
||||
// disable physics until we have enough information about our new location to not cause craziness.
|
||||
resetPhysicsReadyInformation();
|
||||
setIsServerlessMode(errorDomainURL.scheme() != URL_SCHEME_HIFI);
|
||||
if (isServerlessMode()) {
|
||||
loadErrorDomain(errorDomainURL);
|
||||
|
@ -7220,12 +7240,12 @@ void Application::resettingDomain() {
|
|||
void Application::nodeAdded(SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::EntityServer) {
|
||||
if (_failedToConnectToEntityServer && !_entityServerConnectionTimer.isActive()) {
|
||||
_failedToConnectToEntityServer = false;
|
||||
_octreeProcessor.stopSafeLanding();
|
||||
_octreeProcessor.startSafeLanding();
|
||||
_failedToConnectToEntityServer = false;
|
||||
} else if (_entityServerConnectionTimer.isActive()) {
|
||||
_entityServerConnectionTimer.stop();
|
||||
}
|
||||
_octreeProcessor.startSafeLanding();
|
||||
_entityServerConnectionTimer.setInterval(ENTITY_SERVER_CONNECTION_TIMEOUT);
|
||||
_entityServerConnectionTimer.start();
|
||||
}
|
||||
|
@ -7300,7 +7320,7 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
_octreeProcessor.nodeKilled(node);
|
||||
|
||||
_entityEditSender.nodeKilled(node);
|
||||
|
||||
|
||||
if (node->getType() == NodeType::AudioMixer) {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "audioMixerKilled");
|
||||
} else if (node->getType() == NodeType::EntityServer) {
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include <ModelScriptingInterface.h>
|
||||
|
||||
#include "Sound.h"
|
||||
#include "VisionSqueeze.h"
|
||||
|
||||
class GLCanvas;
|
||||
class FaceTracker;
|
||||
|
@ -364,6 +365,9 @@ public:
|
|||
void forceLoginWithTokens(const QString& tokens);
|
||||
void setConfigFileURL(const QString& fileUrl);
|
||||
|
||||
// used by preferences and HMDScriptingInterface...
|
||||
VisionSqueeze& getVisionSqueeze() { return _visionSqueeze; }
|
||||
|
||||
signals:
|
||||
void svoImportRequested(const QString& url);
|
||||
|
||||
|
@ -731,6 +735,7 @@ private:
|
|||
|
||||
bool _loginDialogPoppedUp{ false };
|
||||
bool _desktopRootItemCreated{ false };
|
||||
|
||||
bool _developerMenuVisible{ false };
|
||||
QString _previousAvatarSkeletonModel;
|
||||
float _previousAvatarTargetScale;
|
||||
|
@ -837,5 +842,7 @@ private:
|
|||
bool _resumeAfterLoginDialogActionTaken_SafeToRun { false };
|
||||
bool _startUpFinished { false };
|
||||
bool _overrideEntry { false };
|
||||
|
||||
VisionSqueeze _visionSqueeze;
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
58
interface/src/MacHelper.cpp
Executable file
58
interface/src/MacHelper.cpp
Executable file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// MacHelper.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Howard Stearns
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "InterfaceLogging.h"
|
||||
#include "MacHelper.h"
|
||||
#include <NodeList.h>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <IOKit/IOMessage.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
// The type definitions in these variables come from IOKit, which includes a definition of Duration that conflicts with ours.
|
||||
// So... we include these definitions here rather than in the .h, as the .h is included in Application.cpp which
|
||||
// uses Duration.
|
||||
static io_connect_t root_port;
|
||||
static IONotificationPortRef notifyPortRef;
|
||||
static io_object_t notifierObject;
|
||||
static void* refCon;
|
||||
|
||||
static void sleepHandler(void* refCon, io_service_t service, natural_t messageType, void* messageArgument) {
|
||||
if (messageType == kIOMessageSystemHasPoweredOn) {
|
||||
qCInfo(interfaceapp) << "Waking up from sleep or hybernation.";
|
||||
QMetaObject::invokeMethod(DependencyManager::get<NodeList>().data(), "noteAwakening", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MacHelper::MacHelper() {
|
||||
#ifdef Q_OS_MAC
|
||||
root_port = IORegisterForSystemPower(refCon, ¬ifyPortRef, sleepHandler, ¬ifierObject);
|
||||
if (root_port == 0) {
|
||||
qCWarning(interfaceapp) << "IORegisterForSystemPower failed";
|
||||
return;
|
||||
}
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(),
|
||||
IONotificationPortGetRunLoopSource(notifyPortRef),
|
||||
kCFRunLoopCommonModes);
|
||||
#endif
|
||||
}
|
||||
|
||||
MacHelper::~MacHelper() {
|
||||
#ifdef Q_OS_MAC
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
|
||||
IONotificationPortGetRunLoopSource(notifyPortRef),
|
||||
kCFRunLoopCommonModes);
|
||||
IODeregisterForSystemPower(¬ifierObject);
|
||||
IOServiceClose(root_port);
|
||||
IONotificationPortDestroy(notifyPortRef);
|
||||
#endif
|
||||
}
|
21
interface/src/MacHelper.h
Executable file
21
interface/src/MacHelper.h
Executable file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// MacHelper.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Howard Stearns
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DependencyManager.h"
|
||||
|
||||
class MacHelper : public Dependency {
|
||||
public:
|
||||
MacHelper();
|
||||
~MacHelper();
|
||||
};
|
||||
|
|
@ -266,8 +266,13 @@ Menu::Menu() {
|
|||
// Settings > Graphics...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Graphics...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
qApp->showDialog(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"),
|
||||
QString("hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog");
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
tablet->pushOntoStack("hifi/dialogs/graphics/GraphicsSettings.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
}
|
||||
});
|
||||
|
||||
// Settings > Security...
|
||||
|
|
|
@ -92,7 +92,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
|
|||
RenderScriptingInterface::getInstance()->setShadowsEnabled(true);
|
||||
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME);
|
||||
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.5f);
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.75f);
|
||||
|
||||
break;
|
||||
case PerformancePreset::MID:
|
||||
|
@ -114,7 +114,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
|
|||
|
||||
RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale);
|
||||
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.75f);
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.25f);
|
||||
|
||||
break;
|
||||
case PerformancePreset::UNKNOWN:
|
||||
|
|
213
interface/src/VisionSqueeze.cpp
Normal file
213
interface/src/VisionSqueeze.cpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
//
|
||||
// VisionSqueeze.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Seth Alves on 2019-3-13.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "VisionSqueeze.h"
|
||||
|
||||
#include <glm/gtx/matrix_decompose.hpp>
|
||||
#include <glm/gtc/epsilon.hpp>
|
||||
|
||||
#include <display-plugins/hmd/HmdDisplayPlugin.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
VisionSqueeze::VisionSqueeze() :
|
||||
_visionSqueezeEnabled(_visionSqueezeEnabledSetting.get()),
|
||||
_visionSqueezeRatioX(_visionSqueezeRatioXSetting.get()),
|
||||
_visionSqueezeRatioY(_visionSqueezeRatioYSetting.get()),
|
||||
_visionSqueezeUnSqueezeDelay(_visionSqueezeUnSqueezeDelaySetting.get()),
|
||||
_visionSqueezeUnSqueezeSpeed(_visionSqueezeUnSqueezeSpeedSetting.get()),
|
||||
_visionSqueezeTransition(_visionSqueezeTransitionSetting.get()),
|
||||
_visionSqueezePerEye(_visionSqueezePerEyeSetting.get()),
|
||||
_visionSqueezeGroundPlaneY(_visionSqueezeGroundPlaneYSetting.get()),
|
||||
_visionSqueezeSpotlightSize(_visionSqueezeSpotlightSizeSetting.get()),
|
||||
_visionSqueezeTurningXFactor(_visionSqueezeTurningXFactorSetting.get()),
|
||||
_visionSqueezeTurningYFactor(_visionSqueezeTurningYFactorSetting.get()) {
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeEnabled(bool value) {
|
||||
if (value != _visionSqueezeEnabled) {
|
||||
_visionSqueezeEnabled = value;
|
||||
_visionSqueezeEnabledSetting.set(_visionSqueezeEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeRatioX(float value) {
|
||||
if (value != _visionSqueezeRatioX) {
|
||||
_visionSqueezeRatioX = value;
|
||||
_visionSqueezeRatioXSetting.set(_visionSqueezeRatioX);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeRatioY(float value) {
|
||||
if (value != _visionSqueezeRatioY) {
|
||||
_visionSqueezeRatioY = value;
|
||||
_visionSqueezeRatioYSetting.set(_visionSqueezeRatioY);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeUnSqueezeDelay(float value) {
|
||||
if (value != _visionSqueezeUnSqueezeDelay) {
|
||||
_visionSqueezeUnSqueezeDelay = value;
|
||||
_visionSqueezeUnSqueezeDelaySetting.set(_visionSqueezeUnSqueezeDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeUnSqueezeSpeed(float value) {
|
||||
if (value != _visionSqueezeUnSqueezeSpeed) {
|
||||
_visionSqueezeUnSqueezeSpeed = value;
|
||||
_visionSqueezeUnSqueezeSpeedSetting.set(_visionSqueezeUnSqueezeSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeTransition(float value) {
|
||||
if (value != _visionSqueezeTransition) {
|
||||
_visionSqueezeTransition = value;
|
||||
_visionSqueezeTransitionSetting.set(_visionSqueezeTransition);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezePerEye(int value) {
|
||||
if (value != _visionSqueezePerEye) {
|
||||
_visionSqueezePerEye = value;
|
||||
_visionSqueezePerEyeSetting.set(_visionSqueezePerEye);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeGroundPlaneY(float value) {
|
||||
if (value != _visionSqueezeGroundPlaneY) {
|
||||
_visionSqueezeGroundPlaneY = value;
|
||||
_visionSqueezeGroundPlaneYSetting.set(_visionSqueezeGroundPlaneY);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeSpotlightSize(float value) {
|
||||
if (value != _visionSqueezeSpotlightSize) {
|
||||
_visionSqueezeSpotlightSize = value;
|
||||
_visionSqueezeSpotlightSizeSetting.set(_visionSqueezeSpotlightSize);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeTurningXFactor(float value) {
|
||||
if (value != _visionSqueezeTurningXFactor) {
|
||||
_visionSqueezeTurningXFactor = value;
|
||||
_visionSqueezeTurningXFactorSetting.set(_visionSqueezeTurningXFactor);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::setVisionSqueezeTurningYFactor(float value) {
|
||||
if (value != _visionSqueezeTurningYFactor) {
|
||||
_visionSqueezeTurningYFactor = value;
|
||||
_visionSqueezeTurningYFactorSetting.set(_visionSqueezeTurningYFactor);
|
||||
}
|
||||
}
|
||||
|
||||
void VisionSqueeze::updateVisionSqueeze(const glm::mat4& sensorToWorldMatrix, float deltaTime) {
|
||||
|
||||
const float SENSOR_TO_WORLD_TRANS_EPSILON = 0.0001f;
|
||||
const float SENSOR_TO_WORLD_TRANS_Y_EPSILON = 0.01f;
|
||||
const float SENSOR_TO_WORLD_TRANS_ITS_A_TELEPORT_SQUARED = 2.0f;
|
||||
const float SENSOR_TO_WORLD_ROT_EPSILON = 0.000005f;
|
||||
const float SENSOR_TO_WORLD_ROT_ITS_A_SNAP_TURN = 0.99f;
|
||||
const float VISION_SQUEEZE_TP_LOCKOUT = 0.1f; // seconds
|
||||
|
||||
glm::vec3 scale;
|
||||
glm::quat rotation;
|
||||
glm::vec3 translation;
|
||||
glm::vec3 skew;
|
||||
glm::vec4 perspective;
|
||||
glm::decompose(sensorToWorldMatrix, scale, rotation, translation, skew, perspective);
|
||||
|
||||
if (!_visionSqueezeEnabled) {
|
||||
_squeezeVision = false;
|
||||
_squeezeVisionTurning = false;
|
||||
} else if (_visionSqueezeLockout > 0.0f) {
|
||||
_visionSqueezeLockout -= deltaTime;
|
||||
} else {
|
||||
_squeezeVision = false;
|
||||
_squeezeVisionTurning = false;
|
||||
glm::vec3 absTransDelta = glm::abs(translation - _prevTranslation);
|
||||
float rotDot = fabsf(glm::dot(rotation, _prevRotation));
|
||||
|
||||
// if the avatar has just teleported or snap-turned, briefly disable triggering of vision-squeeze
|
||||
if (glm::length2(translation - _prevTranslation) > SENSOR_TO_WORLD_TRANS_ITS_A_TELEPORT_SQUARED ||
|
||||
rotDot < SENSOR_TO_WORLD_ROT_ITS_A_SNAP_TURN) {
|
||||
_visionSqueezeLockout = VISION_SQUEEZE_TP_LOCKOUT;
|
||||
_squeezeVision = true;
|
||||
_squeezeVisionTurning = true;
|
||||
} else if (rotDot < 1.0f - SENSOR_TO_WORLD_ROT_EPSILON) {
|
||||
_squeezeVision = true;
|
||||
_squeezeVisionTurning = true;
|
||||
} else if (absTransDelta.x > SENSOR_TO_WORLD_TRANS_EPSILON ||
|
||||
absTransDelta.y > SENSOR_TO_WORLD_TRANS_Y_EPSILON ||
|
||||
absTransDelta.z > SENSOR_TO_WORLD_TRANS_EPSILON) {
|
||||
_squeezeVision = true;
|
||||
_squeezeVisionTurning = false;
|
||||
}
|
||||
}
|
||||
|
||||
_prevTranslation = translation;
|
||||
_prevRotation = rotation;
|
||||
|
||||
static quint64 lastSqueezeTime = 0;
|
||||
quint64 now = usecTimestampNow();
|
||||
static float visionSqueezeX = 0.0f; // 0.0 -- unobstructed, 1.0 -- fully blocked
|
||||
static float visionSqueezeY = 0.0f; // 0.0 -- unobstructed, 1.0 -- fully blocked
|
||||
|
||||
if (_squeezeVision) {
|
||||
float ratioX = getVisionSqueezeRatioX();
|
||||
float ratioY = getVisionSqueezeRatioY();
|
||||
|
||||
if (ratioX >= 0.0f) {
|
||||
if (_squeezeVisionTurning) {
|
||||
ratioX += (1.0f - ratioX) * getVisionSqueezeTurningXFactor();
|
||||
}
|
||||
float newVisionSqueezeX = ratioX;
|
||||
if (newVisionSqueezeX >= visionSqueezeX) {
|
||||
lastSqueezeTime = now;
|
||||
visionSqueezeX = newVisionSqueezeX;
|
||||
}
|
||||
} else {
|
||||
visionSqueezeX = -1.0f;
|
||||
}
|
||||
|
||||
if (ratioY >= 0.0f) {
|
||||
float newVisionSqueezeY = ratioY;
|
||||
if (newVisionSqueezeY >= visionSqueezeY) {
|
||||
lastSqueezeTime = now;
|
||||
visionSqueezeY = newVisionSqueezeY;
|
||||
}
|
||||
} else {
|
||||
visionSqueezeY = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float unsqueezeAmount = deltaTime * getVisionSqueezeUnSqueezeSpeed();
|
||||
if (now - lastSqueezeTime > getVisionSqueezeUnSqueezeDelay() * USECS_PER_SECOND) {
|
||||
visionSqueezeX -= unsqueezeAmount;
|
||||
if (visionSqueezeX < 0.0f) {
|
||||
visionSqueezeX = -1.0f;
|
||||
}
|
||||
visionSqueezeY -= unsqueezeAmount;
|
||||
if (visionSqueezeY < 0.0f) {
|
||||
visionSqueezeY = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<HmdDisplayPlugin> hmdDisplayPlugin =
|
||||
std::dynamic_pointer_cast<HmdDisplayPlugin>(qApp->getActiveDisplayPlugin());
|
||||
if (hmdDisplayPlugin) {
|
||||
hmdDisplayPlugin->updateVisionSqueezeParameters(visionSqueezeX, visionSqueezeY,
|
||||
getVisionSqueezeTransition(),
|
||||
getVisionSqueezePerEye(),
|
||||
getVisionSqueezeGroundPlaneY(),
|
||||
getVisionSqueezeSpotlightSize());
|
||||
}
|
||||
}
|
108
interface/src/VisionSqueeze.h
Normal file
108
interface/src/VisionSqueeze.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
//
|
||||
// VisionSqueeze.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Seth Alves on 2019-3-13.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_VisionSqueeze_h
|
||||
#define hifi_VisionSqueeze_h
|
||||
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
|
||||
static const float DEFAULT_VISION_SQUEEZE_TURNING_X_FACTOR = 0.51f;
|
||||
static const float DEFAULT_VISION_SQUEEZE_TURNING_Y_FACTOR = 0.36f;
|
||||
static const float DEFAULT_VISION_SQUEEZE_UNSQUEEZE_DELAY = 0.2f; // seconds
|
||||
static const float DEFAULT_VISION_SQUEEZE_UNSQUEEZE_SPEED = 3.0f;
|
||||
static const float DEFAULT_VISION_SQUEEZE_TRANSITION = 0.25f;
|
||||
static const int DEFAULT_VISION_SQUEEZE_PER_EYE = 1;
|
||||
static const float DEFAULT_VISION_SQUEEZE_GROUND_PLANE_Y = 0.0f;
|
||||
static const float DEFAULT_VISION_SQUEEZE_SPOTLIGHT_SIZE = 6.0f;
|
||||
|
||||
|
||||
class VisionSqueeze {
|
||||
|
||||
public:
|
||||
|
||||
VisionSqueeze();
|
||||
|
||||
bool getVisionSqueezeEnabled() const { return _visionSqueezeEnabled; }
|
||||
void setVisionSqueezeEnabled(bool value);
|
||||
float getVisionSqueezeRatioX() const { return _visionSqueezeRatioX; }
|
||||
float getVisionSqueezeRatioY() const { return _visionSqueezeRatioY; }
|
||||
void setVisionSqueezeRatioX(float value);
|
||||
void setVisionSqueezeRatioY(float value);
|
||||
float getVisionSqueezeUnSqueezeDelay() const { return _visionSqueezeUnSqueezeDelay; }
|
||||
void setVisionSqueezeUnSqueezeDelay(float value);
|
||||
float getVisionSqueezeUnSqueezeSpeed() const { return _visionSqueezeUnSqueezeSpeed; }
|
||||
void setVisionSqueezeUnSqueezeSpeed(float value);
|
||||
float getVisionSqueezeTransition() const { return _visionSqueezeTransition; }
|
||||
void setVisionSqueezeTransition(float value);
|
||||
int getVisionSqueezePerEye() const { return _visionSqueezePerEye; }
|
||||
void setVisionSqueezePerEye(int value);
|
||||
float getVisionSqueezeGroundPlaneY() const { return _visionSqueezeGroundPlaneY; }
|
||||
void setVisionSqueezeGroundPlaneY(float value);
|
||||
float getVisionSqueezeSpotlightSize() const { return _visionSqueezeSpotlightSize; }
|
||||
void setVisionSqueezeSpotlightSize(float value);
|
||||
float getVisionSqueezeTurningXFactor() const { return _visionSqueezeTurningXFactor; }
|
||||
void setVisionSqueezeTurningXFactor(float value);
|
||||
float getVisionSqueezeTurningYFactor() const { return _visionSqueezeTurningYFactor; }
|
||||
void setVisionSqueezeTurningYFactor(float value);
|
||||
|
||||
void updateVisionSqueeze(const glm::mat4& sensorToWorldMatrix, float deltaTime);
|
||||
|
||||
// state variable accessors used by Application.cpp...
|
||||
bool getSqueezeVision() const { return _squeezeVision; }
|
||||
void setSqueezeVision(bool value) { _squeezeVision = value; }
|
||||
bool getSqueezeVisionTurning() const { return _squeezeVisionTurning; }
|
||||
void setSqueezeVisionTurning(bool value) { _squeezeVisionTurning = value; }
|
||||
|
||||
private:
|
||||
Setting::Handle<bool> _visionSqueezeEnabledSetting {"visionSqueezeEnabled", false};
|
||||
Setting::Handle<float> _visionSqueezeRatioXSetting {"visionSqueezeRatioX", 0.0f};
|
||||
Setting::Handle<float> _visionSqueezeRatioYSetting {"visionSqueezeRatioY", 0.0f};
|
||||
Setting::Handle<float> _visionSqueezeUnSqueezeDelaySetting {"visionSqueezeUnSqueezeDelay",
|
||||
DEFAULT_VISION_SQUEEZE_UNSQUEEZE_DELAY};
|
||||
Setting::Handle<float> _visionSqueezeUnSqueezeSpeedSetting {"visionSqueezeUnSqueezeSpeed",
|
||||
DEFAULT_VISION_SQUEEZE_UNSQUEEZE_SPEED};
|
||||
Setting::Handle<float> _visionSqueezeTransitionSetting {"visionSqueezeTransition", DEFAULT_VISION_SQUEEZE_TRANSITION};
|
||||
Setting::Handle<float> _visionSqueezePerEyeSetting {"visionSqueezePerEye", DEFAULT_VISION_SQUEEZE_PER_EYE};
|
||||
Setting::Handle<float> _visionSqueezeGroundPlaneYSetting {"visionSqueezeGroundPlaneY",
|
||||
DEFAULT_VISION_SQUEEZE_GROUND_PLANE_Y};
|
||||
Setting::Handle<float> _visionSqueezeSpotlightSizeSetting {"visionSqueezeSpotlightSize",
|
||||
DEFAULT_VISION_SQUEEZE_SPOTLIGHT_SIZE};
|
||||
Setting::Handle<float> _visionSqueezeTurningXFactorSetting {"visionSqueezeTurningXFactor",
|
||||
DEFAULT_VISION_SQUEEZE_TURNING_X_FACTOR};
|
||||
Setting::Handle<float> _visionSqueezeTurningYFactorSetting {"visionSqueezeTurningYFactor",
|
||||
DEFAULT_VISION_SQUEEZE_TURNING_Y_FACTOR};
|
||||
|
||||
|
||||
// these are readable and writable from the scripting interface (on a different thread), so make them atomic
|
||||
std::atomic<bool> _visionSqueezeEnabled { false };
|
||||
std::atomic<float> _visionSqueezeRatioX { 0.0f };
|
||||
std::atomic<float> _visionSqueezeRatioY { 0.0f };
|
||||
std::atomic<float> _visionSqueezeUnSqueezeDelay { DEFAULT_VISION_SQUEEZE_UNSQUEEZE_DELAY }; // seconds
|
||||
std::atomic<float> _visionSqueezeUnSqueezeSpeed { DEFAULT_VISION_SQUEEZE_UNSQUEEZE_SPEED };
|
||||
std::atomic<float> _visionSqueezeTransition { DEFAULT_VISION_SQUEEZE_TRANSITION };
|
||||
std::atomic<int> _visionSqueezePerEye { DEFAULT_VISION_SQUEEZE_PER_EYE };
|
||||
std::atomic<float> _visionSqueezeGroundPlaneY { DEFAULT_VISION_SQUEEZE_GROUND_PLANE_Y };
|
||||
std::atomic<float> _visionSqueezeSpotlightSize { DEFAULT_VISION_SQUEEZE_SPOTLIGHT_SIZE };
|
||||
std::atomic<float> _visionSqueezeTurningXFactor { DEFAULT_VISION_SQUEEZE_TURNING_X_FACTOR };
|
||||
std::atomic<float> _visionSqueezeTurningYFactor { DEFAULT_VISION_SQUEEZE_TURNING_Y_FACTOR };
|
||||
|
||||
bool _squeezeVision { false };
|
||||
bool _squeezeVisionTurning { false };
|
||||
|
||||
float _visionSqueezeLockout { 0.0 };
|
||||
glm::vec3 _prevTranslation;
|
||||
glm::quat _prevRotation;
|
||||
};
|
||||
|
||||
#endif // hifi_VisionSqueeze_h
|
|
@ -574,6 +574,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
|
|||
|
||||
avatar->die();
|
||||
queuePhysicsChange(avatar);
|
||||
avatar->removeOrb();
|
||||
|
||||
// remove this avatar's entities from the tree now, if we wait (as we did previously) for this Avatar's destructor
|
||||
// it might not fire until after we create a new instance for the same remote avatar, which creates a race
|
||||
|
|
|
@ -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]));
|
||||
|
|
|
@ -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,4 +6207,3 @@ void MyAvatar::sendPacket(const QUuid& entityID) const {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -1839,6 +1839,10 @@ public:
|
|||
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 +2196,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
|
||||
|
@ -2823,6 +2854,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);
|
||||
|
|
|
@ -294,8 +294,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 +312,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());
|
||||
|
|
|
@ -75,6 +75,7 @@ void OtherAvatar::createOrb() {
|
|||
properties.setType(EntityTypes::Sphere);
|
||||
properties.setAlpha(1.0f);
|
||||
properties.setColor(getLoadingOrbColor(_loadingStatus));
|
||||
properties.setName("Loading Avatar " + getID().toString());
|
||||
properties.setPrimitiveMode(PrimitiveMode::LINES);
|
||||
properties.getPulse().setMin(0.5f);
|
||||
properties.getPulse().setMax(1.0f);
|
||||
|
@ -201,6 +202,7 @@ void OtherAvatar::computeShapeLOD() {
|
|||
break;
|
||||
case workload::Region::UNKNOWN:
|
||||
case workload::Region::INVALID:
|
||||
case workload::Region::R4:
|
||||
case workload::Region::R3:
|
||||
default:
|
||||
newLOD = BodyLOD::Sphere;
|
||||
|
|
|
@ -114,7 +114,11 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
|
|||
if (renderer) {
|
||||
renderer->processDatagram(*message, sendingNode);
|
||||
if (_safeLanding && _safeLanding->isTracking()) {
|
||||
_safeLanding->addToSequence(renderer->getLastOctreeMessageSequence());
|
||||
OCTREE_PACKET_SEQUENCE thisSequence = renderer->getLastOctreeMessageSequence();
|
||||
_safeLanding->addToSequence(thisSequence);
|
||||
if (_safeLandingSequenceStart == SafeLanding::INVALID_SEQUENCE) {
|
||||
_safeLandingSequenceStart = thisSequence;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,8 +128,8 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
|
|||
// Read sequence #
|
||||
OCTREE_PACKET_SEQUENCE completionNumber;
|
||||
message->readPrimitive(&completionNumber);
|
||||
if (_safeLanding) {
|
||||
_safeLanding->finishSequence(0, completionNumber);
|
||||
if (_safeLanding && _safeLanding->isTracking()) {
|
||||
_safeLanding->finishSequence(_safeLandingSequenceStart, completionNumber);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -153,6 +157,13 @@ void OctreePacketProcessor::stopSafeLanding() {
|
|||
}
|
||||
}
|
||||
|
||||
void OctreePacketProcessor::resetSafeLanding() {
|
||||
if (_safeLanding) {
|
||||
_safeLanding->reset();
|
||||
}
|
||||
_safeLandingSequenceStart = SafeLanding::INVALID_SEQUENCE;
|
||||
}
|
||||
|
||||
bool OctreePacketProcessor::safeLandingIsActive() const {
|
||||
return _safeLanding && _safeLanding->isTracking();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
void startSafeLanding();
|
||||
void updateSafeLanding();
|
||||
void stopSafeLanding();
|
||||
void resetSafeLanding();
|
||||
bool safeLandingIsActive() const;
|
||||
bool safeLandingIsComplete() const;
|
||||
|
||||
|
@ -43,6 +44,7 @@ private slots:
|
|||
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
|
||||
private:
|
||||
OCTREE_PACKET_SEQUENCE _safeLandingSequenceStart { SafeLanding::INVALID_SEQUENCE };
|
||||
std::unique_ptr<SafeLanding> _safeLanding;
|
||||
};
|
||||
#endif // hifi_OctreePacketProcessor_h
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "Application.h"
|
||||
|
||||
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
||||
|
||||
CalculateEntityLoadingPriority SafeLanding::entityLoadingOperatorElevateCollidables = [](const EntityItem& entityItem) {
|
||||
const int COLLIDABLE_ENTITY_PRIORITY = 10.0f;
|
||||
|
@ -25,8 +24,8 @@ CalculateEntityLoadingPriority SafeLanding::entityLoadingOperatorElevateCollidab
|
|||
};
|
||||
|
||||
namespace {
|
||||
template<typename T> bool lessThanWraparound(int a, int b) {
|
||||
constexpr int MAX_T_VALUE = std::numeric_limits<T>::max();
|
||||
template<typename T> bool lessThanWraparound(int32_t a, int32_t b) {
|
||||
constexpr int32_t MAX_T_VALUE = std::numeric_limits<T>::max();
|
||||
if (b <= a) {
|
||||
b += MAX_T_VALUE;
|
||||
}
|
||||
|
@ -34,7 +33,7 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
bool SafeLanding::SequenceLessThan::operator()(const int& a, const int& b) const {
|
||||
bool SafeLanding::SequenceLessThan::operator()(const OCTREE_PACKET_SEQUENCE& a, const OCTREE_PACKET_SEQUENCE& b) const {
|
||||
return lessThanWraparound<OCTREE_PACKET_SEQUENCE>(a, b);
|
||||
}
|
||||
|
||||
|
@ -46,8 +45,8 @@ void SafeLanding::startTracking(QSharedPointer<EntityTreeRenderer> entityTreeRen
|
|||
_entityTreeRenderer = entityTreeRenderer;
|
||||
_trackedEntities.clear();
|
||||
_maxTrackedEntityCount = 0;
|
||||
_initialStart = INVALID_SEQUENCE;
|
||||
_initialEnd = INVALID_SEQUENCE;
|
||||
_sequenceStart = SafeLanding::INVALID_SEQUENCE;
|
||||
_sequenceEnd = SafeLanding::INVALID_SEQUENCE;
|
||||
_sequenceNumbers.clear();
|
||||
_trackingEntities = true;
|
||||
_startTime = usecTimestampNow();
|
||||
|
@ -72,7 +71,7 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
|
|||
if (entity && !entity->isLocalEntity() && entity->getCreated() < _startTime) {
|
||||
_trackedEntities.emplace(entityID, entity);
|
||||
|
||||
int trackedEntityCount = (int)_trackedEntities.size();
|
||||
int32_t trackedEntityCount = (int32_t)_trackedEntities.size();
|
||||
if (trackedEntityCount > _maxTrackedEntityCount) {
|
||||
_maxTrackedEntityCount = trackedEntityCount;
|
||||
_trackedEntityStabilityCount = 0;
|
||||
|
@ -87,15 +86,15 @@ void SafeLanding::deleteTrackedEntity(const EntityItemID& entityID) {
|
|||
_trackedEntities.erase(entityID);
|
||||
}
|
||||
|
||||
void SafeLanding::finishSequence(int first, int last) {
|
||||
void SafeLanding::finishSequence(OCTREE_PACKET_SEQUENCE first, OCTREE_PACKET_SEQUENCE last) {
|
||||
Locker lock(_lock);
|
||||
if (_trackingEntities) {
|
||||
_initialStart = first;
|
||||
_initialEnd = last;
|
||||
_sequenceStart = first;
|
||||
_sequenceEnd = last;
|
||||
}
|
||||
}
|
||||
|
||||
void SafeLanding::addToSequence(int sequenceNumber) {
|
||||
void SafeLanding::addToSequence(OCTREE_PACKET_SEQUENCE sequenceNumber) {
|
||||
Locker lock(_lock);
|
||||
_sequenceNumbers.insert(sequenceNumber);
|
||||
}
|
||||
|
@ -135,14 +134,13 @@ void SafeLanding::updateTracking() {
|
|||
|
||||
if (_trackedEntities.empty()) {
|
||||
// no more tracked entities --> check sequenceNumbers
|
||||
if (_initialStart != INVALID_SEQUENCE) {
|
||||
if (_sequenceStart != SafeLanding::INVALID_SEQUENCE) {
|
||||
bool shouldStop = false;
|
||||
{
|
||||
Locker lock(_lock);
|
||||
int sequenceSize = _initialStart <= _initialEnd ? _initialEnd - _initialStart:
|
||||
_initialEnd + SEQUENCE_MODULO - _initialStart;
|
||||
auto startIter = _sequenceNumbers.find(_initialStart);
|
||||
auto endIter = _sequenceNumbers.find(_initialEnd - 1);
|
||||
auto sequenceSize = _sequenceEnd - _sequenceStart; // this works even in rollover case
|
||||
auto startIter = _sequenceNumbers.find(_sequenceStart);
|
||||
auto endIter = _sequenceNumbers.find(_sequenceEnd - 1);
|
||||
|
||||
bool missingSequenceNumbers = qApp->isMissingSequenceNumbers();
|
||||
shouldStop = (sequenceSize == 0 ||
|
||||
|
@ -159,31 +157,41 @@ void SafeLanding::updateTracking() {
|
|||
|
||||
void SafeLanding::stopTracking() {
|
||||
Locker lock(_lock);
|
||||
_trackingEntities = false;
|
||||
if (_entityTreeRenderer) {
|
||||
auto entityTree = _entityTreeRenderer->getTree();
|
||||
disconnect(std::const_pointer_cast<EntityTree>(entityTree).get(),
|
||||
&EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity);
|
||||
disconnect(std::const_pointer_cast<EntityTree>(entityTree).get(),
|
||||
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
|
||||
_entityTreeRenderer.reset();
|
||||
if (_trackingEntities) {
|
||||
_trackingEntities = false;
|
||||
if (_entityTreeRenderer) {
|
||||
auto entityTree = _entityTreeRenderer->getTree();
|
||||
disconnect(std::const_pointer_cast<EntityTree>(entityTree).get(),
|
||||
&EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity);
|
||||
disconnect(std::const_pointer_cast<EntityTree>(entityTree).get(),
|
||||
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
|
||||
_entityTreeRenderer.reset();
|
||||
}
|
||||
EntityTreeRenderer::setEntityLoadingPriorityFunction(_prevEntityLoadingPriorityOperator);
|
||||
}
|
||||
EntityTreeRenderer::setEntityLoadingPriorityFunction(_prevEntityLoadingPriorityOperator);
|
||||
}
|
||||
|
||||
void SafeLanding::reset() {
|
||||
_trackingEntities = false;
|
||||
_trackedEntities.clear();
|
||||
_maxTrackedEntityCount = 0;
|
||||
_sequenceStart = SafeLanding::INVALID_SEQUENCE;
|
||||
_sequenceEnd = SafeLanding::INVALID_SEQUENCE;
|
||||
}
|
||||
|
||||
bool SafeLanding::trackingIsComplete() const {
|
||||
return !_trackingEntities && (_initialStart != INVALID_SEQUENCE);
|
||||
return !_trackingEntities && (_sequenceStart != SafeLanding::INVALID_SEQUENCE);
|
||||
}
|
||||
|
||||
float SafeLanding::loadingProgressPercentage() {
|
||||
Locker lock(_lock);
|
||||
static const int MINIMUM_TRACKED_ENTITY_STABILITY_COUNT = 15;
|
||||
|
||||
float entityReadyPercentage = 0.0f;
|
||||
if (_maxTrackedEntityCount > 0) {
|
||||
entityReadyPercentage = ((_maxTrackedEntityCount - _trackedEntities.size()) / (float)_maxTrackedEntityCount);
|
||||
}
|
||||
|
||||
constexpr int32_t MINIMUM_TRACKED_ENTITY_STABILITY_COUNT = 15;
|
||||
if (_trackedEntityStabilityCount < MINIMUM_TRACKED_ENTITY_STABILITY_COUNT) {
|
||||
entityReadyPercentage *= 0.20f;
|
||||
}
|
||||
|
@ -203,8 +211,22 @@ bool SafeLanding::isEntityPhysicsReady(const EntityItemPointer& entity) {
|
|||
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
|
||||
auto space = _entityTreeRenderer->getWorkloadSpace();
|
||||
uint8_t region = space ? space->getRegion(entity->getSpaceIndex()) : (uint8_t)workload::Region::INVALID;
|
||||
bool shouldBePhysical = region < workload::Region::R3 && entity->shouldBePhysical();
|
||||
return (!shouldBePhysical || entity->isInPhysicsSimulation() || modelEntity->computeShapeFailedToLoad());
|
||||
|
||||
// Note: the meanings of the workload regions are:
|
||||
// R1 = in physics simulation and willing to own simulation
|
||||
// R2 = in physics simulation but does NOT want to own simulation
|
||||
// R3 = not in physics simulation but kinematically animated when velocities are non-zero
|
||||
// R4 = sorted by workload and found to be outside R3
|
||||
// UNKNOWN = known to workload but not yet sorted
|
||||
// INVALID = not known to workload
|
||||
// So any entity sorted into R3 or R4 is definitelyNotPhysical
|
||||
|
||||
bool definitelyNotPhysical = region == workload::Region::R3 ||
|
||||
region == workload::Region::R4 ||
|
||||
!entity->shouldBePhysical() ||
|
||||
modelEntity->unableToLoadCollisionShape();
|
||||
bool definitelyPhysical = entity->isInPhysicsSimulation();
|
||||
return definitelyNotPhysical || definitelyPhysical;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,20 +234,24 @@ bool SafeLanding::isEntityPhysicsReady(const EntityItemPointer& entity) {
|
|||
}
|
||||
|
||||
void SafeLanding::debugDumpSequenceIDs() const {
|
||||
int p = -1;
|
||||
qCDebug(interfaceapp) << "Sequence set size:" << _sequenceNumbers.size();
|
||||
for (auto s: _sequenceNumbers) {
|
||||
if (p == -1) {
|
||||
p = s;
|
||||
qCDebug(interfaceapp) << "First:" << s;
|
||||
} else {
|
||||
|
||||
auto itr = _sequenceNumbers.begin();
|
||||
OCTREE_PACKET_SEQUENCE p = SafeLanding::INVALID_SEQUENCE;
|
||||
if (itr != _sequenceNumbers.end()) {
|
||||
p = (*itr);
|
||||
qCDebug(interfaceapp) << "First:" << (int32_t)p;
|
||||
++itr;
|
||||
while (itr != _sequenceNumbers.end()) {
|
||||
OCTREE_PACKET_SEQUENCE s = *itr;
|
||||
if (s != p + 1) {
|
||||
qCDebug(interfaceapp) << "Gap from" << p << "to" << s << "(exclusive)";
|
||||
qCDebug(interfaceapp) << "Gap from" << (int32_t)p << "to" << (int32_t)s << "(exclusive)";
|
||||
p = s;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
if (p != SafeLanding::INVALID_SEQUENCE) {
|
||||
qCDebug(interfaceapp) << "Last:" << p;
|
||||
}
|
||||
}
|
||||
if (p != -1) {
|
||||
qCDebug(interfaceapp) << "Last:" << p;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityDynamicInterface.h"
|
||||
|
||||
|
@ -27,14 +29,18 @@ class EntityItemID;
|
|||
|
||||
class SafeLanding : public QObject {
|
||||
public:
|
||||
static constexpr OCTREE_PACKET_SEQUENCE MAX_SEQUENCE = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max();
|
||||
static constexpr OCTREE_PACKET_SEQUENCE INVALID_SEQUENCE = MAX_SEQUENCE; // not technically invalid, but close enough
|
||||
|
||||
void startTracking(QSharedPointer<EntityTreeRenderer> entityTreeRenderer);
|
||||
void updateTracking();
|
||||
void stopTracking();
|
||||
void reset();
|
||||
bool isTracking() const { return _trackingEntities; }
|
||||
bool trackingIsComplete() const;
|
||||
|
||||
void finishSequence(int first, int last); // 'last' exclusive.
|
||||
void addToSequence(int sequenceNumber);
|
||||
void finishSequence(OCTREE_PACKET_SEQUENCE first, OCTREE_PACKET_SEQUENCE last); // 'last' exclusive.
|
||||
void addToSequence(OCTREE_PACKET_SEQUENCE sequenceNumber);
|
||||
float loadingProgressPercentage();
|
||||
|
||||
private slots:
|
||||
|
@ -52,24 +58,22 @@ private:
|
|||
using EntityMap = std::map<EntityItemID, EntityItemPointer>;
|
||||
EntityMap _trackedEntities;
|
||||
|
||||
static constexpr int INVALID_SEQUENCE = -1;
|
||||
int _initialStart { INVALID_SEQUENCE };
|
||||
int _initialEnd { INVALID_SEQUENCE };
|
||||
int _maxTrackedEntityCount { 0 };
|
||||
int _trackedEntityStabilityCount { 0 };
|
||||
OCTREE_PACKET_SEQUENCE _sequenceStart { INVALID_SEQUENCE };
|
||||
OCTREE_PACKET_SEQUENCE _sequenceEnd { INVALID_SEQUENCE };
|
||||
int32_t _maxTrackedEntityCount { 0 };
|
||||
int32_t _trackedEntityStabilityCount { 0 };
|
||||
|
||||
quint64 _startTime { 0 };
|
||||
|
||||
struct SequenceLessThan {
|
||||
bool operator()(const int& a, const int& b) const;
|
||||
bool operator()(const OCTREE_PACKET_SEQUENCE& a, const OCTREE_PACKET_SEQUENCE& b) const;
|
||||
};
|
||||
|
||||
std::set<int, SequenceLessThan> _sequenceNumbers;
|
||||
using SequenceSet = std::set<OCTREE_PACKET_SEQUENCE, SequenceLessThan>;
|
||||
SequenceSet _sequenceNumbers;
|
||||
|
||||
static CalculateEntityLoadingPriority entityLoadingOperatorElevateCollidables;
|
||||
CalculateEntityLoadingPriority _prevEntityLoadingPriorityOperator { nullptr };
|
||||
|
||||
static const int SEQUENCE_MODULO;
|
||||
};
|
||||
|
||||
#endif // hifi_SafeLanding_h
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -111,10 +111,11 @@ void DesktopScriptingInterface::show(const QString& path, const QString& title)
|
|||
InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString& sourceUrl, const QVariantMap& properties) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
InteractiveWindowPointer interactiveWindow = nullptr;
|
||||
BLOCKING_INVOKE_METHOD(this, "createWindow",
|
||||
BLOCKING_INVOKE_METHOD(this, "createWindowOnThread",
|
||||
Q_RETURN_ARG(InteractiveWindowPointer, interactiveWindow),
|
||||
Q_ARG(QString, sourceUrl),
|
||||
Q_ARG(QVariantMap, properties));
|
||||
Q_ARG(QVariantMap, properties),
|
||||
Q_ARG(QThread*, QThread::currentThread()));
|
||||
return interactiveWindow;
|
||||
}
|
||||
|
||||
|
@ -129,3 +130,16 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString&
|
|||
|
||||
return new InteractiveWindow(sourceUrl, properties);
|
||||
}
|
||||
|
||||
InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread) {
|
||||
// The offscreen surface already validates against non-local QML sources, but we also need to ensure that
|
||||
// if we create top level QML, like dock widgets or other types of QQuickView containing desktop windows
|
||||
// that the source URL is permitted
|
||||
const auto& urlValidator = OffscreenQmlSurface::getUrlValidator();
|
||||
if (!urlValidator(sourceUrl)) {
|
||||
return nullptr;
|
||||
}
|
||||
InteractiveWindowPointer window = new InteractiveWindow(sourceUrl, properties);
|
||||
window->moveToThread(targetThread);
|
||||
return window;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,8 @@ private:
|
|||
static int flagAlwaysOnTop() { return AlwaysOnTop; }
|
||||
static int flagCloseButtonHides() { return CloseButtonHides; }
|
||||
|
||||
Q_INVOKABLE InteractiveWindowPointer createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread);
|
||||
|
||||
static QVariantMap getDockArea();
|
||||
|
||||
Q_INVOKABLE static QVariantMap getPresentationMode();
|
||||
|
|
|
@ -236,3 +236,83 @@ QVariant HMDScriptingInterface::getPlayAreaRect() {
|
|||
QVector<glm::vec3> HMDScriptingInterface::getSensorPositions() {
|
||||
return qApp->getActiveDisplayPlugin()->getSensorPositions();
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeRatioX() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeRatioX();
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeRatioY() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeRatioY();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeRatioX(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeRatioX(value);
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeRatioY(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeRatioY(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeUnSqueezeDelay() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeUnSqueezeDelay();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeUnSqueezeDelay(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeUnSqueezeDelay(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeUnSqueezeSpeed() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeUnSqueezeSpeed();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeUnSqueezeSpeed(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeUnSqueezeSpeed(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeTransition() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeTransition();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeTransition(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeTransition(value);
|
||||
}
|
||||
|
||||
int HMDScriptingInterface::getVisionSqueezePerEye() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezePerEye();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezePerEye(int value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezePerEye(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeGroundPlaneY() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeGroundPlaneY();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeGroundPlaneY(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeGroundPlaneY(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeSpotlightSize() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeSpotlightSize();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeSpotlightSize(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeSpotlightSize(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeTurningXFactor() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeTurningXFactor();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeTurningXFactor(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeTurningXFactor(value);
|
||||
}
|
||||
|
||||
float HMDScriptingInterface::getVisionSqueezeTurningYFactor() const {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeTurningYFactor();
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::setVisionSqueezeTurningYFactor(float value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeTurningYFactor(value);
|
||||
}
|
||||
|
|
|
@ -62,10 +62,29 @@ 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>
|
||||
*
|
||||
* @property {number} visionSqueezeRatioX=0.0 - The amount of vision squeeze for the x-axis when moving, range <code>0.0</code>
|
||||
* – <code>1.0</code>.
|
||||
* @property {number} visionSqueezeRatioY=0.0 - The amount of vision squeeze for the y-axis when moving, range <code>0.0</code>
|
||||
* – <code>1.0</code>.
|
||||
* @property {number} visionSqueezeTurningXFactor=0.51 - The additional amount of vision squeeze for the x-axis when turning,
|
||||
* range <code>0.0</code> – <code>1.0</code>.
|
||||
* @property {number} visionSqueezeTurningYFactor=0.36 - <em>Currently unused.</em>
|
||||
* @property {number} visionSqueezeUnSqueezeDelay=0.2 - The delay in undoing the vision squeeze effect after motion stops, in
|
||||
* seconds.
|
||||
* @property {number} visionSqueezeUnSqueezeSpeed=3.0 - How quickly the vision squeeze effect fades, once
|
||||
* <code>visionSqueezeUnSqueezeDelay</code> has passed.
|
||||
* @property {number} visionSqueezeTransition=0.25 - How tightly vision is squeezed, range <code>0.01</code> –
|
||||
* <code>0.7</code>.
|
||||
* @property {number} visionSqueezePerEye=1 - <code>1</code> if each eye gets a tube to see through, <code>0</code> if the face
|
||||
* gets a tube.
|
||||
* @property {number} visionSqueezeGroundPlaneY=0.0 - Adjusts how far below the camera the vision squeeze grid is displayed at.
|
||||
* @property {number} visionSqueezeSpotlightSize=6.0 - The diameter of the circle of vision squeeze grid that is illuminated
|
||||
* around the camera.
|
||||
*/
|
||||
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -84,6 +103,17 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
|
|||
Q_PROPERTY(QVariant playArea READ getPlayAreaRect);
|
||||
Q_PROPERTY(QVector<glm::vec3> sensorPositions READ getSensorPositions);
|
||||
|
||||
Q_PROPERTY(float visionSqueezeRatioX READ getVisionSqueezeRatioX WRITE setVisionSqueezeRatioX);
|
||||
Q_PROPERTY(float visionSqueezeRatioY READ getVisionSqueezeRatioY WRITE setVisionSqueezeRatioY);
|
||||
Q_PROPERTY(float visionSqueezeUnSqueezeDelay READ getVisionSqueezeUnSqueezeDelay WRITE setVisionSqueezeUnSqueezeDelay);
|
||||
Q_PROPERTY(float visionSqueezeUnSqueezeSpeed READ getVisionSqueezeUnSqueezeSpeed WRITE setVisionSqueezeUnSqueezeSpeed);
|
||||
Q_PROPERTY(float visionSqueezeTransition READ getVisionSqueezeTransition WRITE setVisionSqueezeTransition);
|
||||
Q_PROPERTY(int visionSqueezePerEye READ getVisionSqueezePerEye WRITE setVisionSqueezePerEye);
|
||||
Q_PROPERTY(float visionSqueezeGroundPlaneY READ getVisionSqueezeGroundPlaneY WRITE setVisionSqueezeGroundPlaneY);
|
||||
Q_PROPERTY(float visionSqueezeSpotlightSize READ getVisionSqueezeSpotlightSize WRITE setVisionSqueezeSpotlightSize);
|
||||
Q_PROPERTY(float visionSqueezeTurningXFactor READ getVisionSqueezeTurningXFactor WRITE setVisionSqueezeTurningXFactor);
|
||||
Q_PROPERTY(float visionSqueezeTurningYFactor READ getVisionSqueezeTurningYFactor WRITE setVisionSqueezeTurningYFactor);
|
||||
|
||||
public:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -339,6 +369,27 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE void openTablet(bool contextualMode = false);
|
||||
|
||||
float getVisionSqueezeRatioX() const;
|
||||
float getVisionSqueezeRatioY() const;
|
||||
void setVisionSqueezeRatioX(float value);
|
||||
void setVisionSqueezeRatioY(float value);
|
||||
float getVisionSqueezeUnSqueezeDelay() const;
|
||||
void setVisionSqueezeUnSqueezeDelay(float value);
|
||||
float getVisionSqueezeUnSqueezeSpeed() const;
|
||||
void setVisionSqueezeUnSqueezeSpeed(float value);
|
||||
float getVisionSqueezeTransition() const;
|
||||
void setVisionSqueezeTransition(float value);
|
||||
int getVisionSqueezePerEye() const;
|
||||
void setVisionSqueezePerEye(int value);
|
||||
float getVisionSqueezeGroundPlaneY() const;
|
||||
void setVisionSqueezeGroundPlaneY(float value);
|
||||
float getVisionSqueezeSpotlightSize() const;
|
||||
void setVisionSqueezeSpotlightSize(float value);
|
||||
float getVisionSqueezeTurningXFactor() const;
|
||||
void setVisionSqueezeTurningXFactor(float value);
|
||||
float getVisionSqueezeTurningYFactor() const;
|
||||
void setVisionSqueezeTurningYFactor(float value);
|
||||
|
||||
signals:
|
||||
/**jsdoc
|
||||
* Triggered when a request to show or hide models of the HMD hand controllers is made using
|
||||
|
|
|
@ -221,4 +221,6 @@ QStringList PlatformInfoScriptingInterface::getPlatformTierNames() {
|
|||
return platformTierNames;
|
||||
}
|
||||
|
||||
|
||||
bool PlatformInfoScriptingInterface::isRenderMethodDeferredCapable() {
|
||||
return platform::Profiler::isRenderMethodDeferredCapable();
|
||||
}
|
||||
|
|
|
@ -245,7 +245,12 @@ public slots:
|
|||
*/
|
||||
QStringList getPlatformTierNames();
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* Gets whether the current hardware can render using the Deferred method.
|
||||
* @function PlatformInfo.isRenderMethodDeferredCapable
|
||||
* @returns {bool} <code>true</code> if the current hardware can render using the Deferred method; <code>false</code> otherwise.
|
||||
*/
|
||||
bool isRenderMethodDeferredCapable();
|
||||
};
|
||||
|
||||
#endif // hifi_PlatformInfoScriptingInterface_h
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -94,7 +94,7 @@ void AvatarInputs::setShowBubbleTools(bool showBubbleTools) {
|
|||
return;
|
||||
|
||||
_showBubbleTools = showBubbleTools;
|
||||
showBubbleToolsSetting.set(_showAudioTools);
|
||||
showBubbleToolsSetting.set(_showBubbleTools);
|
||||
emit showBubbleToolsChanged(_showBubbleTools);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -51,6 +51,36 @@ static const QStringList KNOWN_SCHEMES = QStringList() << "http" << "https" << "
|
|||
|
||||
static const int DEFAULT_HEIGHT = 60;
|
||||
|
||||
QmlWindowProxy::QmlWindowProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qmlObject, parent) {
|
||||
_qmlWindow = qmlObject;
|
||||
}
|
||||
|
||||
void QmlWindowProxy::parentNativeWindowToMainWindow() {
|
||||
#ifdef Q_OS_WIN
|
||||
if (!_qmlWindow) {
|
||||
return;
|
||||
}
|
||||
const auto nativeWindowProperty = _qmlWindow->property("nativeWindow");
|
||||
if (nativeWindowProperty.isNull() || !nativeWindowProperty.isValid()) {
|
||||
return;
|
||||
}
|
||||
const auto nativeWindow = qvariant_cast<QQuickWindow*>(nativeWindowProperty);
|
||||
SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId());
|
||||
#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();
|
||||
}
|
||||
|
||||
static void dockWidgetDeleter(DockWidget* dockWidget) {
|
||||
dockWidget->deleteLater();
|
||||
}
|
||||
|
@ -85,13 +115,13 @@ void InteractiveWindow::forwardKeyReleaseEvent(int key, int modifiers) {
|
|||
* @property {string} [title="InteractiveWindow] - The title of the window.
|
||||
* @property {Vec2} [position] - The initial position of the window, in pixels.
|
||||
* @property {Vec2} [size] - The initial size of the window, in pixels
|
||||
* @property {boolean} [visible=true] - <code>true</code> to make the window visible when created, <code>false</code> to make
|
||||
* @property {boolean} [visible=true] - <code>true</code> to make the window visible when created, <code>false</code> to make
|
||||
* it invisible.
|
||||
* @property {InteractiveWindow.PresentationMode} [presentationMode=Desktop.PresentationMode.VIRTUAL] -
|
||||
* <code>Desktop.PresentationMode.VIRTUAL</code> to display the window inside Interface, <code>.NATIVE</code> to display it
|
||||
* @property {InteractiveWindow.PresentationMode} [presentationMode=Desktop.PresentationMode.VIRTUAL] -
|
||||
* <code>Desktop.PresentationMode.VIRTUAL</code> to display the window inside Interface, <code>.NATIVE</code> to display it
|
||||
* as its own separate window.
|
||||
* @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a <code>NATIVE</code> window is
|
||||
* displayed. If used, the window is docked to the specified edge of the Interface window, otherwise the window is
|
||||
* @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a <code>NATIVE</code> window is
|
||||
* displayed. If used, the window is docked to the specified edge of the Interface window, otherwise the window is
|
||||
* displayed as its own separate window.
|
||||
* @property {InteractiveWindow.AdditionalFlags} [additionalFlags=0] - Window behavior flags in addition to "native window flags" (minimize/maximize/close),
|
||||
* set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}.
|
||||
|
@ -107,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;
|
||||
|
@ -124,7 +160,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
|
|||
auto mainWindow = qApp->getWindow();
|
||||
_dockWidget = std::shared_ptr<DockWidget>(new DockWidget(title, mainWindow), dockWidgetDeleter);
|
||||
auto quickView = _dockWidget->getQuickView();
|
||||
|
||||
|
||||
Application::setupQmlSurface(quickView->rootContext() , true);
|
||||
|
||||
//add any whitelisted callbacks
|
||||
|
@ -160,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)),
|
||||
|
@ -176,14 +216,13 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
|
|||
});
|
||||
|
||||
_dockWidget->setSource(QUrl(sourceUrl));
|
||||
|
||||
mainWindow->addDockWidget(dockArea, _dockWidget.get());
|
||||
} else {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) {
|
||||
_qmlWindow = object;
|
||||
context->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
|
||||
_qmlWindowProxy = std::shared_ptr<QmlWindowProxy>(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter);
|
||||
context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy);
|
||||
if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) {
|
||||
object->setProperty(ADDITIONAL_FLAGS_PROPERTY, properties[ADDITIONAL_FLAGS_PROPERTY].toUInt());
|
||||
}
|
||||
|
@ -208,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)),
|
||||
|
@ -242,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();
|
||||
|
@ -249,212 +292,153 @@ void InteractiveWindow::sendToQml(const QVariant& message) {
|
|||
QMetaObject::invokeMethod(rootItem, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
}
|
||||
} else {
|
||||
QMetaObject::invokeMethod(_qmlWindow, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveWindow::emitScriptEvent(const QVariant& scriptMessage) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, scriptMessage));
|
||||
} else {
|
||||
emit scriptEventReceived(scriptMessage);
|
||||
}
|
||||
emit scriptEventReceived(scriptMessage);
|
||||
}
|
||||
|
||||
void InteractiveWindow::emitWebEvent(const QVariant& webMessage) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, webMessage));
|
||||
} else {
|
||||
emit webEventReceived(webMessage);
|
||||
}
|
||||
emit webEventReceived(webMessage);
|
||||
}
|
||||
|
||||
void InteractiveWindow::close() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "close");
|
||||
return;
|
||||
if (_qmlWindowProxy) {
|
||||
QObject* qmlWindow = _qmlWindowProxy->getQmlWindow();
|
||||
if (qmlWindow) {
|
||||
qmlWindow->deleteLater();
|
||||
}
|
||||
_qmlWindowProxy->deleteLater();
|
||||
}
|
||||
|
||||
if (_qmlWindow) {
|
||||
_qmlWindow->deleteLater();
|
||||
if (_interactiveWindowProxy) {
|
||||
_interactiveWindowProxy->deleteLater();
|
||||
}
|
||||
|
||||
qApp->getWindow()->removeDockWidget(_dockWidget.get());
|
||||
if (_dockWidget) {
|
||||
auto window = qApp->getWindow();
|
||||
if (QThread::currentThread() != window->thread()) {
|
||||
BLOCKING_INVOKE_METHOD(window, "removeDockWidget", Q_ARG(QDockWidget*, _dockWidget.get()));
|
||||
} else {
|
||||
window->removeDockWidget(_dockWidget.get());
|
||||
}
|
||||
}
|
||||
_dockWidget = nullptr;
|
||||
_qmlWindow = nullptr;
|
||||
_qmlWindowProxy = nullptr;
|
||||
_interactiveWindowProxy = nullptr;
|
||||
}
|
||||
|
||||
void InteractiveWindow::show() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "show");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_qmlWindow) {
|
||||
QMetaObject::invokeMethod(_qmlWindow, "show", Qt::DirectConnection);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "show");
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveWindow::raise() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "raise");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_qmlWindow) {
|
||||
QMetaObject::invokeMethod(_qmlWindow, "raiseWindow", Qt::DirectConnection);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "raiseWindow");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveWindow::setVisible(bool visible) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setVisible", Q_ARG(bool, visible));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_qmlWindow.isNull()) {
|
||||
_qmlWindow->setProperty(INTERACTIVE_WINDOW_VISIBLE_PROPERTY, visible);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_VISIBLE_PROPERTY),
|
||||
Q_ARG(QVariant, visible));
|
||||
}
|
||||
}
|
||||
|
||||
bool InteractiveWindow::isVisible() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
bool result = false;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<InteractiveWindow*>(this), "isVisible", Q_RETURN_ARG(bool, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_qmlWindow.isNull()) {
|
||||
if (!_qmlWindowProxy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _qmlWindow->property(INTERACTIVE_WINDOW_VISIBLE_PROPERTY).toBool();
|
||||
return _qmlWindowProxy->readProperty(INTERACTIVE_WINDOW_VISIBLE_PROPERTY).toBool();
|
||||
}
|
||||
|
||||
glm::vec2 InteractiveWindow::getPosition() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
glm::vec2 result;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<InteractiveWindow*>(this), "getPosition", Q_RETURN_ARG(glm::vec2, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_qmlWindow.isNull()) {
|
||||
if (!_qmlWindowProxy) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_POSITION_PROPERTY).toPointF());
|
||||
return toGlm(_qmlWindowProxy->readProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY).toPointF());
|
||||
}
|
||||
|
||||
void InteractiveWindow::setPosition(const glm::vec2& position) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setPosition", Q_ARG(const glm::vec2&, position));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_qmlWindow.isNull()) {
|
||||
_qmlWindow->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y));
|
||||
QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowPositionForMode", Qt::DirectConnection);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_POSITION_PROPERTY),
|
||||
Q_ARG(QVariant, QPointF(position.x, position.y)));
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "updateInteractiveWindowPositionForMode");
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec2 InteractiveWindow::getSize() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
glm::vec2 result;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<InteractiveWindow*>(this), "getSize", Q_RETURN_ARG(glm::vec2, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_qmlWindow.isNull()) {
|
||||
if (!_qmlWindowProxy) {
|
||||
return {};
|
||||
}
|
||||
return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_SIZE_PROPERTY).toSize());
|
||||
|
||||
return toGlm(_qmlWindowProxy->readProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY).toSize());
|
||||
}
|
||||
|
||||
void InteractiveWindow::setSize(const glm::vec2& size) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setSize", Q_ARG(const glm::vec2&, size));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_qmlWindow.isNull()) {
|
||||
_qmlWindow->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y));
|
||||
QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowSizeForMode", Qt::DirectConnection);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_SIZE_PROPERTY),
|
||||
Q_ARG(QVariant, QSize(size.x, size.y)));
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "updateInteractiveWindowSizeForMode");
|
||||
}
|
||||
}
|
||||
|
||||
QString InteractiveWindow::getTitle() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QString result;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<InteractiveWindow*>(this), "getTitle", Q_RETURN_ARG(QString, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_qmlWindow.isNull()) {
|
||||
if (!_qmlWindowProxy) {
|
||||
return QString();
|
||||
}
|
||||
return _qmlWindow->property(TITLE_PROPERTY).toString();
|
||||
|
||||
return _qmlWindowProxy->readProperty(TITLE_PROPERTY).toString();
|
||||
}
|
||||
|
||||
void InteractiveWindow::setTitle(const QString& title) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setTitle", Q_ARG(const QString&, title));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_qmlWindow.isNull()) {
|
||||
_qmlWindow->setProperty(TITLE_PROPERTY, title);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, TITLE_PROPERTY),
|
||||
Q_ARG(QVariant, title));
|
||||
}
|
||||
}
|
||||
|
||||
int InteractiveWindow::getPresentationMode() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
int result;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<InteractiveWindow*>(this), "getPresentationMode",
|
||||
Q_RETURN_ARG(int, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_qmlWindow.isNull()) {
|
||||
if (!_qmlWindowProxy) {
|
||||
return Virtual;
|
||||
}
|
||||
return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt();
|
||||
|
||||
return _qmlWindowProxy->readProperty(PRESENTATION_MODE_PROPERTY).toInt();
|
||||
}
|
||||
|
||||
void InteractiveWindow::parentNativeWindowToMainWindow() {
|
||||
#ifdef Q_OS_WIN
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "parentNativeWindowToMainWindow");
|
||||
return;
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "parentNativeWindowToMainWindow");
|
||||
}
|
||||
if (_qmlWindow.isNull()) {
|
||||
return;
|
||||
}
|
||||
const auto nativeWindowProperty = _qmlWindow->property("nativeWindow");
|
||||
if (nativeWindowProperty.isNull() || !nativeWindowProperty.isValid()) {
|
||||
return;
|
||||
}
|
||||
const auto nativeWindow = qvariant_cast<QQuickWindow*>(nativeWindowProperty);
|
||||
SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId());
|
||||
#endif
|
||||
}
|
||||
|
||||
void InteractiveWindow::setPresentationMode(int presentationMode) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setPresentationMode", Q_ARG(int, presentationMode));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_qmlWindow.isNull()) {
|
||||
_qmlWindow->setProperty(PRESENTATION_MODE_PROPERTY, presentationMode);
|
||||
if (_qmlWindowProxy) {
|
||||
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, PRESENTATION_MODE_PROPERTY),
|
||||
Q_ARG(QVariant, presentationMode));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,42 @@
|
|||
#include <QtCore/QPointer>
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <QQmlEngine>
|
||||
#include <ui/QmlWrapper.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
class QmlWindowProxy : public QmlWrapper {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlWindowProxy(QObject* qmlObject, QObject* parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void parentNativeWindowToMainWindow();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
namespace InteractiveWindowEnums {
|
||||
Q_NAMESPACE
|
||||
|
||||
|
@ -291,8 +323,9 @@ protected slots:
|
|||
void forwardKeyReleaseEvent(int key, int modifiers);
|
||||
|
||||
private:
|
||||
QPointer<QObject> _qmlWindow;
|
||||
std::shared_ptr<QmlWindowProxy> _qmlWindowProxy;
|
||||
std::shared_ptr<DockWidget> _dockWidget { nullptr };
|
||||
InteractiveWindowProxy *_interactiveWindowProxy{ nullptr };
|
||||
};
|
||||
|
||||
typedef InteractiveWindow* InteractiveWindowPointer;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <Preferences.h>
|
||||
#include <plugins/PluginUtils.h>
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <display-plugins/hmd/HmdDisplayPlugin.h>
|
||||
#include "scripting/RenderScriptingInterface.h"
|
||||
#include "Application.h"
|
||||
#include "DialogsManager.h"
|
||||
|
@ -377,6 +378,33 @@ void setupPreferences() {
|
|||
preference->setDecimals(2);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->bool {
|
||||
return qApp->getVisionSqueeze().getVisionSqueezeEnabled();
|
||||
};
|
||||
auto setter = [](bool value) {
|
||||
qApp->getVisionSqueeze().setVisionSqueezeEnabled(value);
|
||||
};
|
||||
auto preference = new CheckPreference(VR_MOVEMENT, "Enable HMD Comfort Mode", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
const float sliderPositions = 5.0f;
|
||||
auto getter = [sliderPositions]()->float {
|
||||
return roundf(sliderPositions * qApp->getVisionSqueeze().getVisionSqueezeRatioX());
|
||||
};
|
||||
auto setter = [sliderPositions](float value) {
|
||||
float ratio = value / sliderPositions;
|
||||
qApp->getVisionSqueeze().setVisionSqueezeRatioX(ratio);
|
||||
qApp->getVisionSqueeze().setVisionSqueezeRatioY(ratio);
|
||||
};
|
||||
auto preference = new SpinnerSliderPreference(VR_MOVEMENT, "Comfort Mode", getter, setter);
|
||||
preference->setMin(0.0f);
|
||||
preference->setMax(sliderPositions);
|
||||
preference->setStep(1.0f);
|
||||
preference->setDecimals(0);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [myAvatar]()->bool { return myAvatar->getShowPlayArea(); };
|
||||
auto setter = [myAvatar](bool value) { myAvatar->setShowPlayArea(value); };
|
||||
|
|
|
@ -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> –
|
||||
* <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> – <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> –
|
||||
* <code>1.0</code>.
|
||||
* @property {number} innerEndAlpha=0.7 - The opacity at the inner end point of the overlay, <code>0.0</code> –
|
||||
* <code>1.0</code>.
|
||||
* @property {number} outerStartAlpha=0.7 - The opacity at the outer start point of the overlay, <code>0.0</code> –
|
||||
* <code>1.0</code>.
|
||||
* @property {number} outerEndAlpha=0.7 - The opacity at the outer end point of the overlay, <code>0.0</code> –
|
||||
* <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.
|
||||
*/
|
||||
|
|
|
@ -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", {
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
45
launchers/darwin/cmake/macros/SetPackagingParameters.cmake
Normal file
45
launchers/darwin/cmake/macros/SetPackagingParameters.cmake
Normal 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)
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:)];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]];
|
||||
|
||||
|
|
|
@ -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]];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
} 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:
|
||||
|
|
|
@ -94,6 +94,8 @@ protected:
|
|||
CStatic* m_username_banner;
|
||||
CStatic* m_password_banner;
|
||||
|
||||
CStatic* m_version;
|
||||
|
||||
HWND _applicationWND { 0 };
|
||||
|
||||
void drawBackground(CHwndRenderTarget* pRenderTarget);
|
||||
|
|
|
@ -21,38 +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"));
|
||||
CString response;
|
||||
LauncherUtils::ResponseError error = getMostRecentBuild(_latestApplicationURL, _latestVersion, response);
|
||||
if (error == LauncherUtils::ResponseError::NoError) {
|
||||
addToLog(_T("Latest version: ") + _latestVersion);
|
||||
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;
|
||||
} else {
|
||||
_shouldInstall = TRUE;
|
||||
}
|
||||
} else {
|
||||
_hasFailed = true;
|
||||
CString msg;
|
||||
msg.Format(_T("Getting most recent build has failed with error: %d"), error);
|
||||
addToLog(msg);
|
||||
msg.Format(_T("Response: %s"), response);
|
||||
addToLog(msg);
|
||||
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() {
|
||||
|
@ -152,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;
|
||||
|
@ -181,6 +165,7 @@ void LauncherManager::updateProgress(ProcessType processType, float progress) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
_progress = _progressOffset + (1.0f - _progressOffset) * _progress;
|
||||
TRACE("progress = %f\n", _progress);
|
||||
}
|
||||
|
||||
|
@ -228,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;
|
||||
}
|
||||
|
@ -387,39 +372,100 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
|
|||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut,
|
||||
CString& response) {
|
||||
void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& launcherVersionOut,
|
||||
CString& interfaceUrlOut, CString& interfaceVersionOut) {
|
||||
CString contentTypeJson = L"content-type:application/json";
|
||||
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher",
|
||||
L"thunder.highfidelity.com",
|
||||
L"/builds/api/tags/latest?format=json",
|
||||
contentTypeJson, CStringA(),
|
||||
response, false);
|
||||
if (error != LauncherUtils::ResponseError::NoError) {
|
||||
return error;
|
||||
}
|
||||
Json::Value json;
|
||||
if (LauncherUtils::parseJSON(response, json)) {
|
||||
int count = json["count"].isInt() ? json["count"].asInt() : 0;
|
||||
if (count > 0 && json["results"].isArray()) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (json["results"][i].isObject()) {
|
||||
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());
|
||||
std::function<void(CString, int)> httpCallback = [&](CString response, int err) {
|
||||
LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err);
|
||||
if (error == LauncherUtils::ResponseError::NoError) {
|
||||
Json::Value json;
|
||||
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 (result["installers"].isObject() &&
|
||||
result["installers"]["windows"].isObject() &&
|
||||
result["installers"]["windows"]["zip_url"].isString()) {
|
||||
urlOut = result["installers"]["windows"]["zip_url"].asCString();
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
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++) {
|
||||
if (json["results"][i].isObject()) {
|
||||
Json::Value result = json["results"][i];
|
||||
if (result["latest_version"].isInt()) {
|
||||
std::string version = std::to_string(result["latest_version"].asInt());
|
||||
interfaceVersionOut = CString(version.c_str());
|
||||
}
|
||||
if (result["installers"].isObject() &&
|
||||
result["installers"]["windows"].isObject() &&
|
||||
result["installers"]["windows"]["zip_url"].isString()) {
|
||||
interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty() || interfaceUrlOut.IsEmpty() || interfaceVersionOut.IsEmpty()) {
|
||||
error = LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
}
|
||||
onMostRecentBuildsReceived(response, error);
|
||||
}
|
||||
};
|
||||
LauncherUtils::httpCallOnThread(L"HQ Launcher",
|
||||
L"thunder.highfidelity.com",
|
||||
L"/builds/api/tags/latest?format=json",
|
||||
contentTypeJson, CStringA(), false, httpCallback);
|
||||
}
|
||||
|
||||
void LauncherManager::onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error) {
|
||||
if (error == LauncherUtils::ResponseError::NoError) {
|
||||
addToLog(_T("Latest launcher version: ") + _latestLauncherVersion);
|
||||
CString currentVersion;
|
||||
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 {
|
||||
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 builds has failed with error: %d"), error);
|
||||
addToLog(msg);
|
||||
msg.Format(_T("Response: %s"), response);
|
||||
addToLog(msg);
|
||||
}
|
||||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username,
|
||||
|
@ -517,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,
|
||||
|
@ -559,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);
|
||||
|
@ -578,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,
|
||||
|
@ -593,33 +651,34 @@ 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);
|
||||
std::function<void(int, bool)> onDownloadFinished = [&](int type, bool error) {
|
||||
if (!error) {
|
||||
onFileDownloaded((ProcessType)type);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (type == ProcessType::DownloadApplication) {
|
||||
addToLog(_T("Error downloading content."));
|
||||
}
|
||||
else {
|
||||
} 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;
|
||||
}
|
||||
|
@ -635,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("");
|
||||
|
|
|
@ -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);
|
||||
LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response);
|
||||
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,31 +90,44 @@ 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 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; };
|
||||
void uninstall() { _shouldUninstall = true; _shouldWait = false; };
|
||||
|
||||
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 onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error);
|
||||
CString _latestApplicationURL;
|
||||
CString _latestVersion;
|
||||
CString _latestLauncherURL;
|
||||
CString _latestLauncherVersion;
|
||||
CString _contentURL;
|
||||
CString _domainURL;
|
||||
CString _version;
|
||||
|
@ -119,6 +135,8 @@ private:
|
|||
CString _tokensJSON;
|
||||
CString _applicationZipPath;
|
||||
CString _contentZipPath;
|
||||
CString _launcherVersion;
|
||||
CString _tempLauncherPath;
|
||||
bool _loggedIn { false };
|
||||
bool _hasFailed { false };
|
||||
BOOL _shouldUpdate { FALSE };
|
||||
|
@ -126,6 +144,15 @@ private:
|
|||
BOOL _shouldInstall { FALSE };
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -470,9 +470,9 @@ BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString
|
|||
|
||||
DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
|
||||
UnzipThreadData& data = *((UnzipThreadData*)lpParameter);
|
||||
uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>(), data.progressCallback);
|
||||
uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>(), data._progressCallback);
|
||||
int mb_size = (int)(size * 0.001f);
|
||||
data.callback(data._type, mb_size);
|
||||
data._callback(data._type, mb_size);
|
||||
delete &data;
|
||||
return 0;
|
||||
}
|
||||
|
@ -480,17 +480,26 @@ DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
|
|||
DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) {
|
||||
DownloadThreadData& data = *((DownloadThreadData*)lpParameter);
|
||||
ProgressCallback progressCallback;
|
||||
progressCallback.setProgressCallback(data.progressCallback);
|
||||
progressCallback.setProgressCallback(data._progressCallback);
|
||||
auto hr = URLDownloadToFile(0, data._url, data._file, 0,
|
||||
static_cast<LPBINDSTATUSCALLBACK>(&progressCallback));
|
||||
data.callback(data._type, hr != S_OK);
|
||||
data._callback(data._type, hr != S_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) {
|
||||
DeleteThreadData& data = *((DeleteThreadData*)lpParameter);
|
||||
BOOL success = LauncherUtils::deleteFileOrDirectory(data._dirPath);
|
||||
data.callback(!success);
|
||||
data._callback(!success);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI LauncherUtils::httpThread(LPVOID lpParameter) {
|
||||
HttpThreadData& data = *((HttpThreadData*)lpParameter);
|
||||
CString response;
|
||||
auto error = LauncherUtils::makeHTTPCall(data._callerName, data._mainUrl, data._dirUrl,
|
||||
data._contentType, data._postData, response, data._isPost);
|
||||
data._callback(response, error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -543,6 +552,26 @@ BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::functio
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
|
||||
const CString& contentType, CStringA& postData, bool isPost,
|
||||
std::function<void(CString, int)> callback) {
|
||||
DWORD myThreadID;
|
||||
HttpThreadData* httpThreadData = new HttpThreadData();
|
||||
httpThreadData->_callerName = callerName;
|
||||
httpThreadData->_mainUrl = mainUrl;
|
||||
httpThreadData->_dirUrl = dirUrl;
|
||||
httpThreadData->_contentType = contentType;
|
||||
httpThreadData->_postData = postData;
|
||||
httpThreadData->_isPost = isPost;
|
||||
httpThreadData->setCallback(callback);
|
||||
HANDLE myHandle = CreateThread(0, 0, httpThread, httpThreadData, 0, &myThreadID);
|
||||
if (myHandle) {
|
||||
CloseHandle(myHandle);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HWND LauncherUtils::executeOnForeground(const CString& path, const CString& params) {
|
||||
SHELLEXECUTEINFO info;
|
||||
info.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||
|
|
|
@ -55,15 +55,15 @@ public:
|
|||
ULONG ulStatusCode, LPCWSTR szStatusText) {
|
||||
float progress = (float)ulProgress / ulProgressMax;
|
||||
if (!isnan(progress)) {
|
||||
onProgressCallback(progress);
|
||||
_onProgressCallback(progress);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
void setProgressCallback(std::function<void(float)> fn) {
|
||||
onProgressCallback = std::bind(fn, std::placeholders::_1);
|
||||
_onProgressCallback = std::bind(fn, std::placeholders::_1);
|
||||
}
|
||||
private:
|
||||
std::function<void(float)> onProgressCallback;
|
||||
std::function<void(float)> _onProgressCallback;
|
||||
};
|
||||
|
||||
enum ResponseError {
|
||||
|
@ -82,14 +82,14 @@ public:
|
|||
int _type;
|
||||
CString _url;
|
||||
CString _file;
|
||||
std::function<void(int, bool)> callback;
|
||||
std::function<void(float)> progressCallback;
|
||||
std::function<void(int, bool)> _callback;
|
||||
std::function<void(float)> _progressCallback;
|
||||
// function(type, errorType)
|
||||
void setCallback(std::function<void(int, bool)> fn) {
|
||||
callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
|
||||
_callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
|
||||
}
|
||||
void setProgressCallback(std::function<void(float)> fn) {
|
||||
progressCallback = std::bind(fn, std::placeholders::_1);
|
||||
_progressCallback = std::bind(fn, std::placeholders::_1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -98,23 +98,36 @@ public:
|
|||
std::string _zipFile;
|
||||
std::string _path;
|
||||
// function(type, size)
|
||||
std::function<void(int, int)> callback;
|
||||
std::function<void(float)> progressCallback;
|
||||
std::function<void(int, int)> _callback;
|
||||
std::function<void(float)> _progressCallback;
|
||||
void setCallback(std::function<void(int, int)> fn) {
|
||||
callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
|
||||
_callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
|
||||
}
|
||||
void setProgressCallback(std::function<void(float)> fn) {
|
||||
progressCallback = std::bind(fn, std::placeholders::_1);
|
||||
_progressCallback = std::bind(fn, std::placeholders::_1);
|
||||
}
|
||||
};
|
||||
|
||||
struct DeleteThreadData {
|
||||
CString _dirPath;
|
||||
std::function<void(bool)> callback;
|
||||
std::function<void(float)> progressCallback;
|
||||
void setCallback(std::function<void(bool)> fn) { callback = std::bind(fn, std::placeholders::_1); }
|
||||
std::function<void(bool)> _callback;
|
||||
std::function<void(float)> _progressCallback;
|
||||
void setCallback(std::function<void(bool)> fn) { _callback = std::bind(fn, std::placeholders::_1); }
|
||||
void setProgressCallback(std::function<void(float)> fn) {
|
||||
progressCallback = std::bind(fn, std::placeholders::_1);
|
||||
_progressCallback = std::bind(fn, std::placeholders::_1);
|
||||
}
|
||||
};
|
||||
|
||||
struct HttpThreadData {
|
||||
CString _callerName;
|
||||
CString _mainUrl;
|
||||
CString _dirUrl;
|
||||
CString _contentType;
|
||||
CStringA _postData;
|
||||
bool _isPost { false };
|
||||
std::function<void(CString, int)> _callback;
|
||||
void setCallback(std::function<void(CString, int)> fn) {
|
||||
_callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -150,6 +163,9 @@ public:
|
|||
std::function<void(int, bool)> callback,
|
||||
std::function<void(float)> progressCallback);
|
||||
static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback);
|
||||
static BOOL httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
|
||||
const CString& contentType, CStringA& postData, bool isPost,
|
||||
std::function<void(CString, int)> callback);
|
||||
|
||||
static CString urlEncodeString(const CString& url);
|
||||
static HWND executeOnForeground(const CString& path, const CString& params);
|
||||
|
@ -159,4 +175,5 @@ private:
|
|||
static DWORD WINAPI unzipThread(LPVOID lpParameter);
|
||||
static DWORD WINAPI downloadThread(LPVOID lpParameter);
|
||||
static DWORD WINAPI deleteDirectoryThread(LPVOID lpParameter);
|
||||
};
|
||||
static DWORD WINAPI httpThread(LPVOID lpParameter);
|
||||
};
|
||||
|
|
45
launchers/win32/cmake/macros/SetPackagingParameters.cmake
Normal file
45
launchers/win32/cmake/macros/SetPackagingParameters.cmake
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -431,7 +431,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
|||
constrained = constraint->apply(tipRelativeRotation);
|
||||
if (constrained) {
|
||||
tipOrientation = tipParentOrientation * tipRelativeRotation;
|
||||
tipRelativeRotation = tipRelativeRotation;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1873,6 +1873,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 +2207,8 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
|
|||
}
|
||||
}
|
||||
|
||||
updateReactions(params);
|
||||
|
||||
_previousControllerParameters = params;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -268,6 +270,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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
* };
|
||||
*
|
||||
|
|
|
@ -47,5 +47,9 @@ void AbstractHMDScriptingInterface::setIPDScale(float IPDScale) {
|
|||
}
|
||||
|
||||
bool AbstractHMDScriptingInterface::isHMDMode() const {
|
||||
return PluginContainer::getInstance().getActiveDisplayPlugin()->isHmd();
|
||||
}
|
||||
auto displayPlugin = PluginContainer::getInstance().getActiveDisplayPlugin();
|
||||
if (displayPlugin) {
|
||||
return displayPlugin->isHmd();
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTextureWithVisionSqueeze.frag
|
||||
//
|
||||
// Draw texture 0 fetched at texcoord.xy
|
||||
//
|
||||
// Created by Seth Alves on 2019-2-15
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include display-plugins/VisionSqueeze.slh@>
|
||||
|
||||
struct DrawTextureWithVisionSqueezeParams {
|
||||
float _visionSqueezeX;
|
||||
float _visionSqueezeY;
|
||||
float _spareA;
|
||||
float _spareB;
|
||||
mat4 _leftProjection;
|
||||
mat4 _rightProjection;
|
||||
mat4 _hmdSensorMatrix;
|
||||
float _visionSqueezeTransition;
|
||||
int _visionSqueezePerEye;
|
||||
float _visionSqueezeGroundPlaneY;
|
||||
float _visionSqueezeSpotlightSize;
|
||||
};
|
||||
|
||||
|
||||
LAYOUT(binding=0) uniform sampler2D colorMap;
|
||||
|
||||
// binding=1 must match drawTextureWithSqueezeParamsSlot in OpenGLDisplayPlugin.h
|
||||
LAYOUT(binding=1) uniform drawTextureWithSqueezeMappingParamsBuffer {
|
||||
DrawTextureWithVisionSqueezeParams params;
|
||||
};
|
||||
|
||||
layout(location=0) in vec2 varTexCoord0;
|
||||
layout(location=0) out vec4 outFragColor;
|
||||
|
||||
|
||||
float getVisionSqueezeX() {
|
||||
return params._visionSqueezeX;
|
||||
}
|
||||
float getVisionSqueezeY() {
|
||||
return params._visionSqueezeY;
|
||||
}
|
||||
float getVisionSqueezeTransitionRatio() {
|
||||
return params._visionSqueezeTransition;
|
||||
}
|
||||
int getVisionSqueezePerEye() {
|
||||
return params._visionSqueezePerEye;
|
||||
}
|
||||
float getVisionSqueezeGroundPlaneY() {
|
||||
return params._visionSqueezeGroundPlaneY;
|
||||
}
|
||||
float getVisionSqueezeSpotlightSize() {
|
||||
return params._visionSqueezeSpotlightSize;
|
||||
}
|
||||
mat4 getProjectionMatrix(float eye) {
|
||||
if (eye == 0.0) {
|
||||
return params._leftProjection;
|
||||
} else {
|
||||
return params._rightProjection;
|
||||
}
|
||||
}
|
||||
mat4 getHMDSensorMatrix() {
|
||||
return params._hmdSensorMatrix;
|
||||
}
|
||||
|
||||
|
||||
void main(void) {
|
||||
|
||||
float side = float(varTexCoord0.x > 0.5);
|
||||
mat4 leftProjectionMatrix = getProjectionMatrix(0.0);
|
||||
vec4 fovTan = extractFovTan(leftProjectionMatrix);
|
||||
vec2 focalPointNDC = extractFocalPoint(fovTan);
|
||||
focalPointNDC.x -= 2.0 * focalPointNDC.x * (1.0 - side);
|
||||
vec2 focalPointUV = 0.5 * (focalPointNDC + vec2(1.0));
|
||||
|
||||
// block edges of vision to avoid sickness
|
||||
vec2 visionSqueezeRatios = vec2(getVisionSqueezeX(), getVisionSqueezeY());
|
||||
bool perEye = getVisionSqueezePerEye() > 0;
|
||||
float frac = squeezeVision(perEye, varTexCoord0, visionSqueezeRatios, getVisionSqueezeTransitionRatio(), focalPointUV);
|
||||
|
||||
if (frac == 0.0) {
|
||||
// world only
|
||||
outFragColor = texture(colorMap, varTexCoord0);
|
||||
} else {
|
||||
// grid on the floor only or mixed
|
||||
mat4 hmdSensorMatrix = getHMDSensorMatrix();
|
||||
mat4 projectionMatrix = getProjectionMatrix(side);
|
||||
mat4 projectionInverse = inverse(projectionMatrix);
|
||||
float groundPlaneY = getVisionSqueezeGroundPlaneY();
|
||||
float spotLightSize = getVisionSqueezeSpotlightSize();
|
||||
vec4 gridColor = vec4(gridFloor(varTexCoord0, hmdSensorMatrix, projectionInverse, groundPlaneY, spotLightSize), 1.0);
|
||||
|
||||
vec4 preSqueezeColor = texture(colorMap, varTexCoord0);
|
||||
// mix between grid and world
|
||||
outFragColor = mix(preSqueezeColor, gridColor, frac);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
VERTEX gpu::vertex::DrawUnitQuadTexcoord
|
|
@ -392,6 +392,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
|
||||
_drawTexturePipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTexture), scissorState);
|
||||
|
||||
_drawTextureSqueezePipeline =
|
||||
gpu::Pipeline::create(gpu::Shader::createProgram(shader::display_plugins::program::DrawTextureWithVisionSqueeze), scissorState);
|
||||
|
||||
_linearToSRGBPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureLinearToSRGB), scissorState);
|
||||
|
||||
_SRGBToLinearPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureSRGBToLinear), scissorState);
|
||||
|
@ -407,6 +410,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
void OpenGLDisplayPlugin::uncustomizeContext() {
|
||||
|
||||
_drawTexturePipeline.reset();
|
||||
_drawTextureSqueezePipeline.reset();
|
||||
_linearToSRGBPipeline.reset();
|
||||
_SRGBToLinearPipeline.reset();
|
||||
_cursorPipeline.reset();
|
||||
|
@ -629,6 +633,10 @@ void OpenGLDisplayPlugin::compositePointer() {
|
|||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::setupCompositeScenePipeline(gpu::Batch& batch) {
|
||||
batch.setPipeline(_drawTexturePipeline);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeScene() {
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
@ -637,8 +645,8 @@ void OpenGLDisplayPlugin::compositeScene() {
|
|||
batch.setStateScissorRect(ivec4(uvec2(), _compositeFramebuffer->getSize()));
|
||||
batch.resetViewTransform();
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setPipeline(_drawTexturePipeline);
|
||||
batch.setResourceTexture(0, _currentFrame->framebuffer->getRenderBuffer(0));
|
||||
setupCompositeScenePipeline(batch);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
@ -958,4 +966,3 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
|
|||
gpu::PipelinePointer OpenGLDisplayPlugin::getRenderTexturePipeline() {
|
||||
return _drawTexturePipeline;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ protected:
|
|||
|
||||
virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; }
|
||||
virtual void compositeLayers();
|
||||
virtual void setupCompositeScenePipeline(gpu::Batch& batch);
|
||||
virtual void compositeScene();
|
||||
virtual void compositePointer();
|
||||
virtual void compositeExtra(){};
|
||||
|
@ -155,6 +156,7 @@ protected:
|
|||
gpu::PipelinePointer _mirrorHUDPipeline;
|
||||
gpu::ShaderPointer _mirrorHUDPS;
|
||||
gpu::PipelinePointer _drawTexturePipeline;
|
||||
gpu::PipelinePointer _drawTextureSqueezePipeline;
|
||||
gpu::PipelinePointer _linearToSRGBPipeline;
|
||||
gpu::PipelinePointer _SRGBToLinearPipeline;
|
||||
gpu::PipelinePointer _cursorPipeline;
|
||||
|
|
106
libraries/display-plugins/src/display-plugins/VisionSqueeze.slh
Normal file
106
libraries/display-plugins/src/display-plugins/VisionSqueeze.slh
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Created by Seth Alves on 2019-2-13.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@if not VISION_SQUEEZE_SLH@>
|
||||
<@def VISION_SQUEEZE_SLH@>
|
||||
|
||||
|
||||
float ellipse(vec2 coord, vec2 centerUV, vec2 semiAxis) {
|
||||
return pow(coord.x - centerUV.x, 2.0) / semiAxis.x + pow(coord.y - centerUV.y, 2.0) / semiAxis.y;
|
||||
}
|
||||
|
||||
vec4 extractFovTan(mat4 m) {
|
||||
mat4 mt = transpose(m);
|
||||
vec4 v;
|
||||
vec4 result;
|
||||
|
||||
// x -- Left
|
||||
v = mt * vec4(1.0, 0.0, 0.0, 1.0);
|
||||
result.x = -(v.z / v.x);
|
||||
// y -- Right
|
||||
v = mt * vec4(-1.0, 0.0, 0.0, 1.0);
|
||||
result.y = (v.z / v.x);
|
||||
// z -- Down
|
||||
v = mt * vec4(0.0, 1.0, 0.0, 1.0);
|
||||
result.z = -(v.z / v.y);
|
||||
// w -- Up
|
||||
v = mt * vec4(0.0, -1.0, 0.0, 1.0);
|
||||
result.w = v.z / v.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
// takes left-side projection matrix, returns NDC for right eye. to get left, invert sign on x coord of result.
|
||||
vec2 extractFocalPoint(vec4 fovTan) {
|
||||
float fovwidth = fovTan.x + fovTan.y;
|
||||
float fovheight = fovTan.z + fovTan.w;
|
||||
vec2 focalPoint = vec2(fovTan.y / fovwidth, (fovTan.z / fovheight) - 0.5f);
|
||||
return focalPoint;
|
||||
}
|
||||
|
||||
float squeezeVision(bool perEye, vec2 varTexCoord0, vec2 visionSqueezeRatios, float transitionRatio, vec2 focalPointUV) {
|
||||
if (visionSqueezeRatios.x == 0.0 && visionSqueezeRatios.y == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
vec2 centerUV;
|
||||
vec2 semiAxis;
|
||||
if (perEye) {
|
||||
// tubes in front of each eye
|
||||
centerUV = focalPointUV;
|
||||
semiAxis = vec2(0.25) - visionSqueezeRatios * 0.25;
|
||||
} else {
|
||||
// one tube in front of face
|
||||
centerUV = vec2(0.5, focalPointUV.y);
|
||||
semiAxis = vec2(0.5) - visionSqueezeRatios * 0.5;
|
||||
}
|
||||
float ellipseValue = ellipse(varTexCoord0, centerUV, semiAxis);
|
||||
float frac = clamp((ellipseValue - 1.0) / clamp(transitionRatio, 0.01, 0.7), 0.0, 1.0);
|
||||
|
||||
return frac;
|
||||
}
|
||||
|
||||
vec3 gridFloor(vec2 varTexCoord0, mat4 hmdSensorMatrix, mat4 projectionInverse, float groundPlaneY, float spotLightSize) {
|
||||
vec4 ndc = vec4(varTexCoord0.x * 4.0 - 1.0 - 2.0 * float(varTexCoord0.x > 0.5), varTexCoord0.y * 2.0 - 1.0, -1.0, 1.0);
|
||||
|
||||
vec4 fragmentEyeCoords = hmdSensorMatrix * projectionInverse * ndc;
|
||||
vec4 near4 = hmdSensorMatrix * vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
vec3 near = (near4 / near4.w).xyz;
|
||||
vec3 far = fragmentEyeCoords.xyz / fragmentEyeCoords.w;
|
||||
|
||||
// intersect a line from near to far with the plane y = groundPlaneY
|
||||
float t = -(near.y - groundPlaneY) / (far.y - near.y);
|
||||
vec2 R = (near + t * (far - near)).xz;
|
||||
|
||||
float lineThickness = 1.5 / length(R);
|
||||
vec4 gridColor = vec4(0.35);
|
||||
vec4 baseColor = vec4(0.1);
|
||||
vec4 skyColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec2 wrapped = fract(R) - 0.5f;
|
||||
vec2 range = abs(wrapped);
|
||||
vec2 speeds = fwidth(R);
|
||||
vec2 pixelRange = range/speeds;
|
||||
float lineWeight = clamp(min(pixelRange.x, pixelRange.y) - lineThickness, 0.0, 1.0);
|
||||
|
||||
float horizonFuzz = 0.02;
|
||||
if (t < 0.0) {
|
||||
return mix(gridColor, skyColor, clamp(0.0, 1.0, -t)).xyz;
|
||||
} else if (t < horizonFuzz) {
|
||||
lineWeight = lineWeight * max(0.0, t);
|
||||
}
|
||||
|
||||
vec4 c = mix(gridColor, baseColor, lineWeight);
|
||||
|
||||
// fade out grid to avoid shimmer
|
||||
float fadeVal = 0.7;
|
||||
return mix(c, baseColor * fadeVal + gridColor * (1.0 - fadeVal),
|
||||
0.1 * clamp((length(R) - spotLightSize), 0.0, 1.0)).xyz;
|
||||
}
|
||||
|
||||
<@endif@>
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2016/02/15
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -113,6 +113,11 @@ void HmdDisplayPlugin::internalDeactivate() {
|
|||
}
|
||||
|
||||
void HmdDisplayPlugin::customizeContext() {
|
||||
|
||||
VisionSqueezeParameters parameters;
|
||||
_visionSqueezeParametersBuffer =
|
||||
gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(VisionSqueezeParameters), (const gpu::Byte*) ¶meters));
|
||||
|
||||
Parent::customizeContext();
|
||||
_hudRenderer.build();
|
||||
}
|
||||
|
@ -478,3 +483,48 @@ HmdDisplayPlugin::~HmdDisplayPlugin() {
|
|||
float HmdDisplayPlugin::stutterRate() const {
|
||||
return _stutterRate.rate();
|
||||
}
|
||||
|
||||
float adjustVisionSqueezeRatioForDevice(float visionSqueezeRatio, float visionSqueezeDeviceLow, float visionSqueezeDeviceHigh) {
|
||||
if (visionSqueezeRatio <= 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float deviceRange = visionSqueezeDeviceHigh - visionSqueezeDeviceLow;
|
||||
const float SQUEEZE_ADJUSTMENT = 0.75f; // magic number picked through experimentation
|
||||
return deviceRange * (SQUEEZE_ADJUSTMENT * visionSqueezeRatio) + visionSqueezeDeviceLow;
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::updateVisionSqueezeParameters(float visionSqueezeX, float visionSqueezeY,
|
||||
float visionSqueezeTransition,
|
||||
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
|
||||
float visionSqueezeSpotlightSize) {
|
||||
|
||||
visionSqueezeX = adjustVisionSqueezeRatioForDevice(visionSqueezeX, _visionSqueezeDeviceLowX, _visionSqueezeDeviceHighX);
|
||||
visionSqueezeY = adjustVisionSqueezeRatioForDevice(visionSqueezeY, _visionSqueezeDeviceLowY, _visionSqueezeDeviceHighY);
|
||||
|
||||
auto& params = _visionSqueezeParametersBuffer.get<VisionSqueezeParameters>();
|
||||
if (params._visionSqueezeX != visionSqueezeX) {
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeX = visionSqueezeX;
|
||||
}
|
||||
if (params._visionSqueezeY != visionSqueezeY) {
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeY = visionSqueezeY;
|
||||
}
|
||||
if (params._visionSqueezeTransition != visionSqueezeTransition) {
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeTransition = visionSqueezeTransition;
|
||||
}
|
||||
if (params._visionSqueezePerEye != visionSqueezePerEye) {
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezePerEye = visionSqueezePerEye;
|
||||
}
|
||||
if (params._visionSqueezeGroundPlaneY != visionSqueezeGroundPlaneY) {
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeGroundPlaneY = visionSqueezeGroundPlaneY;
|
||||
}
|
||||
if (params._visionSqueezeSpotlightSize != visionSqueezeSpotlightSize) {
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeSpotlightSize = visionSqueezeSpotlightSize;
|
||||
}
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::setupCompositeScenePipeline(gpu::Batch& batch) {
|
||||
batch.setPipeline(_drawTextureSqueezePipeline);
|
||||
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._hmdSensorMatrix = _currentPresentFrameInfo.presentPose;
|
||||
batch.setUniformBuffer(drawTextureWithVisionSqueezeParamsSlot, _visionSqueezeParametersBuffer);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,9 @@ public:
|
|||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override;
|
||||
virtual StencilMaskMode getStencilMaskMode() const override { return StencilMaskMode::PAINT; }
|
||||
void updateVisionSqueezeParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition,
|
||||
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
|
||||
float visionSqueezeSpotlightSize);
|
||||
|
||||
signals:
|
||||
void hmdMountedChanged();
|
||||
|
@ -91,6 +94,33 @@ protected:
|
|||
RateCounter<> _stutterRate;
|
||||
|
||||
bool _disablePreview { true };
|
||||
|
||||
class VisionSqueezeParameters {
|
||||
public:
|
||||
float _visionSqueezeX { 0.0f };
|
||||
float _visionSqueezeY { 0.0f };
|
||||
float _spareA { 0.0f };
|
||||
float _spareB { 0.0f };
|
||||
glm::mat4 _leftProjection;
|
||||
glm::mat4 _rightProjection;
|
||||
glm::mat4 _hmdSensorMatrix;
|
||||
float _visionSqueezeTransition { 0.15f };
|
||||
int _visionSqueezePerEye { 0 };
|
||||
float _visionSqueezeGroundPlaneY { 0.0f };
|
||||
float _visionSqueezeSpotlightSize { 0.0f };
|
||||
|
||||
VisionSqueezeParameters() {}
|
||||
};
|
||||
typedef gpu::BufferView UniformBufferView;
|
||||
gpu::BufferView _visionSqueezeParametersBuffer;
|
||||
|
||||
virtual void setupCompositeScenePipeline(gpu::Batch& batch) override;
|
||||
|
||||
float _visionSqueezeDeviceLowX { 0.0f };
|
||||
float _visionSqueezeDeviceHighX { 1.0f };
|
||||
float _visionSqueezeDeviceLowY { 0.0f };
|
||||
float _visionSqueezeDeviceHighY { 1.0f };
|
||||
|
||||
private:
|
||||
ivec4 getViewportForSourceSize(const uvec2& size) const;
|
||||
float getLeftCenterPixel() const;
|
||||
|
@ -112,7 +142,7 @@ private:
|
|||
struct Uniforms {
|
||||
float alpha { 1.0f };
|
||||
} uniforms;
|
||||
|
||||
|
||||
struct Vertex {
|
||||
vec3 pos;
|
||||
vec2 uv;
|
||||
|
@ -126,3 +156,5 @@ private:
|
|||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> render();
|
||||
} _hudRenderer;
|
||||
};
|
||||
|
||||
const int drawTextureWithVisionSqueezeParamsSlot = 1; // must match binding in DrawTextureWithVisionSqueeze.slf
|
||||
|
|
|
@ -282,27 +282,26 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
|
|||
}
|
||||
|
||||
void RenderableModelEntityItem::fetchCollisionGeometryResource() {
|
||||
_compoundShapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCollisionShapeURL());
|
||||
_collisionGeometryResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCollisionShapeURL());
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::computeShapeFailedToLoad() {
|
||||
if (!_compoundShapeResource) {
|
||||
bool RenderableModelEntityItem::unableToLoadCollisionShape() {
|
||||
if (!_collisionGeometryResource) {
|
||||
fetchCollisionGeometryResource();
|
||||
}
|
||||
|
||||
return (_compoundShapeResource && _compoundShapeResource->isFailed());
|
||||
return (_collisionGeometryResource && _collisionGeometryResource->isFailed());
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setShapeType(ShapeType type) {
|
||||
ModelEntityItem::setShapeType(type);
|
||||
auto shapeType = getShapeType();
|
||||
if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
if (!_compoundShapeResource && !getCollisionShapeURL().isEmpty()) {
|
||||
if (!_collisionGeometryResource && !getCollisionShapeURL().isEmpty()) {
|
||||
fetchCollisionGeometryResource();
|
||||
}
|
||||
} else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) {
|
||||
} else if (_collisionGeometryResource && !getCompoundShapeURL().isEmpty()) {
|
||||
// the compoundURL has been set but the shapeType does not agree
|
||||
_compoundShapeResource.reset();
|
||||
_collisionGeometryResource.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,11 +332,11 @@ bool RenderableModelEntityItem::isReadyToComputeShape() const {
|
|||
}
|
||||
|
||||
if (model->isLoaded()) {
|
||||
if (!shapeURL.isEmpty() && !_compoundShapeResource) {
|
||||
if (!shapeURL.isEmpty() && !_collisionGeometryResource) {
|
||||
const_cast<RenderableModelEntityItem*>(this)->fetchCollisionGeometryResource();
|
||||
}
|
||||
|
||||
if (_compoundShapeResource && _compoundShapeResource->isLoaded()) {
|
||||
if (_collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
|
||||
// we have both URLs AND both geometries AND they are both fully loaded.
|
||||
if (_needsInitialSimulation) {
|
||||
// the _model's offset will be wrong until _needsInitialSimulation is false
|
||||
|
@ -368,7 +367,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
}
|
||||
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
if (!_compoundShapeResource || !_compoundShapeResource->isLoaded()) {
|
||||
if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -376,8 +375,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
// should never fall in here when collision model not fully loaded
|
||||
// TODO: assert that all geometries exist and are loaded
|
||||
//assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded());
|
||||
const HFMModel& collisionGeometry = _compoundShapeResource->getHFMModel();
|
||||
//assert(_model && _model->isLoaded() && _collisionGeometryResource && _collisionGeometryResource->isLoaded());
|
||||
const HFMModel& collisionGeometry = _collisionGeometryResource->getHFMModel();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
@ -499,7 +498,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
std::vector<std::shared_ptr<const graphics::Mesh>> meshes;
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
auto& hfmMeshes = _compoundShapeResource->getHFMModel().meshes;
|
||||
auto& hfmMeshes = _collisionGeometryResource->getHFMModel().meshes;
|
||||
meshes.reserve(hfmMeshes.size());
|
||||
for (auto& hfmMesh : hfmMeshes) {
|
||||
meshes.push_back(hfmMesh._mesh);
|
||||
|
@ -727,10 +726,10 @@ int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
|
|||
|
||||
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
||||
auto model = getModel();
|
||||
if (EntityItem::contains(point) && model && _compoundShapeResource && _compoundShapeResource->isLoaded()) {
|
||||
if (EntityItem::contains(point) && model && _collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
|
||||
glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
|
||||
glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
|
||||
return _compoundShapeResource->getHFMModel().convexHullContains(hfmPoint);
|
||||
return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
|
||||
virtual bool isReadyToComputeShape() const override;
|
||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo) override;
|
||||
bool computeShapeFailedToLoad();
|
||||
bool unableToLoadCollisionShape();
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const override;
|
||||
void stopModelOverrideIfNoParent();
|
||||
|
@ -120,7 +120,7 @@ private:
|
|||
bool readyToAnimate() const;
|
||||
void fetchCollisionGeometryResource();
|
||||
|
||||
GeometryResource::Pointer _compoundShapeResource;
|
||||
GeometryResource::Pointer _collisionGeometryResource;
|
||||
std::vector<int> _jointMap;
|
||||
QVariantMap _originalTextures;
|
||||
bool _jointMapCompleted { false };
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue