Merge branch 'master' of github.com:highfidelity/hifi into feat/avatarTools/avatarDoctor

This commit is contained in:
Thijs Wenker 2019-02-15 20:57:20 +01:00
commit 74ce98a075
393 changed files with 5850 additions and 10313 deletions

View file

@ -81,6 +81,25 @@ if (ANDROID)
set(GLES_OPTION ON)
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
add_definitions(-DHIFI_ANDROID_APP=\"${HIFI_ANDROID_APP}\")
if (
(${HIFI_ANDROID_APP} STREQUAL "questInterface") OR
(${HIFI_ANDROID_APP} STREQUAL "questFramePlayer") OR
(${HIFI_ANDROID_APP} STREQUAL "framePlayer")
)
# We know the quest hardware has this extension, so we can force the use of instanced stereo
add_definitions(-DHAVE_EXT_clip_cull_distance)
# We can also use multiview stereo techniques
add_definitions(-DHAVE_OVR_multiview2)
add_definitions(-DHAVE_OVR_multiview)
# We can also use our own foveated textures
add_definitions(-DHAVE_QCOM_texture_foveated)
# if set, the application itself or some library it depends on MUST implement
# `DisplayPluginList getDisplayPlugins()` and `InputPluginList getInputPlugins()`
add_definitions(-DCUSTOM_INPUT_PLUGINS)
add_definitions(-DCUSTOM_DISPLAY_PLUGINS)
set(PLATFORM_PLUGIN_LIBRARIES oculusMobile oculusMobilePlugin)
endif()
else ()
set(PLATFORM_QT_COMPONENTS WebEngine Xml)
endif ()

View file

@ -1,15 +1,8 @@
import com.android.builder.core.BuilderConstants
apply plugin: 'com.android.application'
android {
signingConfigs {
release {
storeFile project.hasProperty("HIFI_ANDROID_KEYSTORE") ? file(HIFI_ANDROID_KEYSTORE) : null
storePassword project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") ? HIFI_ANDROID_KEYSTORE_PASSWORD : ''
keyAlias project.hasProperty("HIFI_ANDROID_KEY_ALIAS") ? HIFI_ANDROID_KEY_ALIAS : ''
keyPassword project.hasProperty("HIFI_ANDROID_KEY_PASSWORD") ? HIFI_ANDROID_KEY_PASSWORD : ''
}
}
compileSdkVersion 28
defaultConfig {
applicationId "io.highfidelity.frameplayer"
@ -32,19 +25,17 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
externalNativeBuild.cmake.path '../../../CMakeLists.txt'
variantFilter { variant ->
def build = variant.buildType.name
if (build == BuilderConstants.RELEASE) {
variant.setIgnore(true)
}
}
externalNativeBuild.cmake.path '../../../CMakeLists.txt'
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: '../../libraries/qt/libs')
//implementation project(':oculus')
implementation project(':qt')
}

View file

@ -24,6 +24,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -54,6 +55,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
public static final String DOMAIN_URL = "url";
public static final String EXTRA_GOTO_USERNAME = "gotousername";
private static final String TAG = "Interface";
public static final String EXTRA_ARGS = "args";
private static final int WEB_DRAWER_RIGHT_MARGIN = 262;
private static final int WEB_DRAWER_BOTTOM_MARGIN = 150;
private static final int NORMAL_DPI = 160;
@ -78,6 +80,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
private boolean nativeEnterBackgroundCallEnqueued = false;
private SlidingDrawer mWebSlidingDrawer;
private boolean mStartInDomain;
// private GvrApi gvrApi;
// Opaque native pointer to the Application C++ object.
// This object is owned by the InterfaceActivity instance and passed to the native methods.
@ -93,8 +96,14 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
public void onCreate(Bundle savedInstanceState) {
super.isLoading = true;
Intent intent = getIntent();
if (intent.hasExtra(DOMAIN_URL) && !intent.getStringExtra(DOMAIN_URL).isEmpty()) {
if (intent.hasExtra(DOMAIN_URL) && !TextUtils.isEmpty(intent.getStringExtra(DOMAIN_URL))) {
intent.putExtra("applicationArguments", "--url " + intent.getStringExtra(DOMAIN_URL));
} else if (intent.hasExtra(EXTRA_ARGS)) {
String args = intent.getStringExtra(EXTRA_ARGS);
if (!TextUtils.isEmpty(args)) {
mStartInDomain = true;
intent.putExtra("applicationArguments", args);
}
}
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
@ -125,7 +134,10 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
getActionBar().hide();
}
});
startActivity(new Intent(this, SplashActivity.class));
Intent splashIntent = new Intent(this, SplashActivity.class);
splashIntent.putExtra(SplashActivity.EXTRA_START_IN_DOMAIN, mStartInDomain);
startActivity(splashIntent);
mVibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
headsetStateReceiver = new HeadsetStateReceiver();
}

View file

@ -9,6 +9,7 @@ import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
@ -27,9 +28,14 @@ public class PermissionChecker extends Activity {
private static final boolean CHOOSE_AVATAR_ON_STARTUP = false;
private static final String TAG = "Interface";
private static final String EXTRA_ARGS = "args";
private String mArgs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mArgs =(getIntent().getStringExtra(EXTRA_ARGS));
Intent myIntent = new Intent(this, BreakpadUploaderService.class);
startService(myIntent);
if (CHOOSE_AVATAR_ON_STARTUP) {
@ -76,6 +82,11 @@ public class PermissionChecker extends Activity {
private void launchActivityWithPermissions(){
Intent i = new Intent(this, InterfaceActivity.class);
if (!TextUtils.isEmpty(mArgs)) {
i.putExtra(EXTRA_ARGS, mArgs);
}
startActivity(i);
finish();
}

View file

@ -7,6 +7,9 @@ import android.view.View;
public class SplashActivity extends Activity {
public static final String EXTRA_START_IN_DOMAIN = "start-in-domain";
private boolean mStartInDomain;
private native void registerLoadCompleteListener();
@Override
@ -36,13 +39,27 @@ public class SplashActivity extends Activity {
}
public void onAppLoadedComplete() {
if (HifiUtils.getInstance().isUserLoggedIn()) {
startActivity(new Intent(this, MainActivity.class));
} else {
Intent menuIntent = new Intent(this, LoginMenuActivity.class);
menuIntent.putExtra(LoginMenuActivity.EXTRA_FINISH_ON_BACK, true);
startActivity(menuIntent);
if (!mStartInDomain) {
if (HifiUtils.getInstance().isUserLoggedIn()) {
startActivity(new Intent(this, MainActivity.class));
} else {
Intent menuIntent = new Intent(this, LoginMenuActivity.class);
menuIntent.putExtra(LoginMenuActivity.EXTRA_FINISH_ON_BACK, true);
startActivity(menuIntent);
}
}
SplashActivity.this.finish();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_START_IN_DOMAIN, mStartInDomain);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mStartInDomain = savedInstanceState.getBoolean(EXTRA_START_IN_DOMAIN, false);
}
}

View file

@ -1,15 +1,8 @@
import com.android.builder.core.BuilderConstants
apply plugin: 'com.android.application'
android {
signingConfigs {
release {
storeFile project.hasProperty("HIFI_ANDROID_KEYSTORE") ? file(HIFI_ANDROID_KEYSTORE) : null
storePassword project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") ? HIFI_ANDROID_KEYSTORE_PASSWORD : ''
keyAlias project.hasProperty("HIFI_ANDROID_KEY_ALIAS") ? HIFI_ANDROID_KEY_ALIAS : ''
keyPassword project.hasProperty("HIFI_ANDROID_KEY_PASSWORD") ? HIFI_ANDROID_KEY_PASSWORD : ''
}
}
compileSdkVersion 28
defaultConfig {
applicationId "io.highfidelity.frameplayer"
@ -33,15 +26,14 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
externalNativeBuild.cmake.path '../../../CMakeLists.txt'
variantFilter { variant ->
def build = variant.buildType.name
if (build == BuilderConstants.RELEASE) {
variant.setIgnore(true)
}
}
externalNativeBuild.cmake.path '../../../CMakeLists.txt'
}
dependencies {

View file

@ -650,6 +650,8 @@ public class QtActivity extends Activity {
if (!keepInterfaceRunning) {
QtApplication.invokeDelegate();
}
QtNative.terminateQt();
QtNative.setActivity(null,null);
}
//---------------------------------------------------------------------------

View file

@ -14,7 +14,7 @@ link_hifi_libraries(
audio avatars octree gpu graphics shaders fbx hfm entities
networking animation recording shared script-engine embedded-webserver
controllers physics plugins midi image
model-networking ktx shaders
material-networking model-networking ktx shaders
)
add_dependencies(${TARGET_NAME} oven)

View file

@ -111,7 +111,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
newView.lodScaleFactor = powf(2.0f, lodLevelOffset);
startNewTraversal(newView, root);
startNewTraversal(newView, root, isFullScene);
// When the viewFrustum changed the sort order may be incorrect, so we re-sort
// and also use the opportunity to cull anything no longer in view
@ -220,9 +220,10 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil
return hasNewChild || hasNewDescendants;
}
void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root) {
void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root,
bool forceFirstPass) {
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root);
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, forceFirstPass);
// there are three types of traversal:
//
// (1) FirstTime = at login --> find everything in view

View file

@ -42,7 +42,7 @@ private:
bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
void startNewTraversal(const DiffTraversal::View& viewFrustum, EntityTreeElementPointer root);
void startNewTraversal(const DiffTraversal::View& viewFrustum, EntityTreeElementPointer root, bool forceFirstPass = false);
bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override;
void preDistributionProcessing() override;

View file

@ -324,12 +324,6 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode*
if (isFullScene) {
// we're forcing a full scene, clear the force in OctreeQueryNode so we don't force it next time again
nodeData->setShouldForceFullScene(false);
} else {
// we aren't forcing a full scene, check if something else suggests we should
isFullScene = nodeData->haveJSONParametersChanged() ||
(nodeData->hasConicalViews() &&
(nodeData->getViewFrustumJustStoppedChanging() ||
nodeData->hasLodChanged()));
}
if (nodeData->isPacketWaiting()) {

View file

@ -300,6 +300,8 @@ Var substringResult
SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags
;Checking lowest bit:
IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
!insertmacro LoadVar ${SecName}_was_installed
IntOp $AR_SecFlags $AR_SecFlags | $R0
IntCmp $AR_SecFlags 1 "leave_${SecName}"
;Section is not selected:
@ -478,18 +480,6 @@ Var GAClientID
;--------------------------------
; Installation types
Section "-Previous Install Cleanup"
; Remove the resources folder so we don't end up including removed QML files
RMDir /r "$INSTDIR\resources"
; delete old assignment-client and domain-server so they're no longer present
; in client only installs.
Delete "$INSTDIR\@DS_EXEC_NAME@"
Delete "$INSTDIR\@AC_EXEC_NAME@"
; delete interface so it's not there for server-only installs
Delete "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
SectionEnd
@CPACK_NSIS_INSTALLATION_TYPES@

View file

@ -205,13 +205,16 @@ endif()
# link required hifi libraries
link_hifi_libraries(
shared workload task octree ktx gpu gl procedural graphics graphics-scripting render
pointers
recording hfm fbx networking model-networking model-baker entities avatars trackers
pointers recording hfm fbx networking material-networking
model-networking model-baker entities avatars trackers
audio audio-client animation script-engine physics
render-utils entities-renderer avatars-renderer ui qml auto-updater midi
controllers plugins image trackers
ui-plugins display-plugins input-plugins
# Platform specific GL libraries
${PLATFORM_GL_BACKEND}
# Plaform specific input & display plugin libraries
${PLATFORM_PLUGIN_LIBRARIES}
shaders
)
@ -330,7 +333,11 @@ if (APPLE)
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/fonts"
"${RESOURCES_DEV_DIR}/fonts"
# add redirect json to macOS builds.
#copy serverless for android
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/serverless"
"${RESOURCES_DEV_DIR}/serverless"
# add redirect json to macOS builds.
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
"${RESOURCES_DEV_DIR}/serverless/redirect.json"

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

View file

@ -1,5 +1,5 @@
//
// Web3DOverlay.qml
// Web3DSurface.qml
//
// Created by Gabriel Calero & Cristian Duarte on Jun 22, 2018
// Copyright 2016 High Fidelity, Inc.

View file

@ -1,275 +0,0 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebEngine 1.5
import controlsUit 1.0
import stylesUit 1.0
import "qrc:////qml//windows"
ScrollingWindow {
id: root
HifiConstants { id: hifi }
//HifiStyles.HifiConstants { id: hifistyles }
title: "Browser"
resizable: true
destroyOnHidden: true
width: 800
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url
property alias webView: webview
signal loadingChanged(int status)
x: 100
y: 100
Component.onCompleted: {
focus = true
shown = true
addressBar.text = webview.url
}
function setProfile(profile) {
webview.profile = profile;
}
function showPermissionsBar(){
permissionsContainer.visible=true;
}
function hidePermissionsBar(){
permissionsContainer.visible=false;
}
function allowPermissions(){
webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true);
hidePermissionsBar();
}
function setAutoAdd(auto) {
desktop.setAutoAdd(auto);
}
Item {
id:item
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Row {
id: buttons
spacing: 4
anchors.top: parent.top
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 8
HiFiGlyphs {
id: back;
enabled: webview.canGoBack;
text: hifi.glyphs.backward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
}
HiFiGlyphs {
id: forward;
enabled: webview.canGoForward;
text: hifi.glyphs.forward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
HiFiGlyphs {
id: reload;
enabled: webview.canGoForward;
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
}
Item {
id: border
height: 48
anchors.top: parent.top
anchors.topMargin: 8
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: buttons.right
anchors.leftMargin: 8
Item {
id: barIcon
width: parent.height
height: parent.height
Image {
source: webview.icon;
x: (parent.height - height) / 2
y: (parent.width - width) / 2
sourceSize: Qt.size(width, height);
verticalAlignment: Image.AlignVCenter;
horizontalAlignment: Image.AlignHCenter
}
}
TextField {
id: addressBar
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: barIcon.right
anchors.leftMargin: 0
anchors.verticalCenter: parent.verticalCenter
focus: true
colorScheme: hifi.colorSchemes.dark
placeholderText: "Enter URL"
Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i")
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
if (text.indexOf("http") != 0) {
text = "http://" + text;
}
root.hidePermissionsBar();
root.keyboardRaised = false;
webview.url = text;
break;
}
}
}
}
Rectangle {
id:permissionsContainer
visible:false
color: "#000000"
width: parent.width
anchors.top: buttons.bottom
height:40
z:100
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 1.0; color: "grey" }
}
RalewayLight {
id: permissionsInfo
anchors.right:permissionsRow.left
anchors.rightMargin: 32
anchors.topMargin:8
anchors.top:parent.top
text: "This site wants to use your microphone/camera"
size: 18
color: hifi.colors.white
}
Row {
id: permissionsRow
spacing: 4
anchors.top:parent.top
anchors.topMargin: 8
anchors.right: parent.right
visible: true
z:101
Button {
id:allow
text: "Allow"
color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 120
enabled: true
onClicked: root.allowPermissions();
z:101
}
Button {
id:block
text: "Block"
color: hifi.buttons.red
colorScheme: root.colorScheme
width: 120
enabled: true
onClicked: root.hidePermissionsBar();
z:101
}
}
}
WebView {
id: webview
url: "https://highfidelity.com/"
profile: FileTypeProfile;
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.Deferred
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
anchors.top: buttons.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
onFeaturePermissionRequested: {
if (feature == 2) { // QWebEnginePage::MediaAudioCapture
grantFeaturePermission(securityOrigin, feature, true);
} else {
permissionsBar.securityOrigin = securityOrigin;
permissionsBar.feature = feature;
root.showPermissionsBar();
}
}
onLoadingChanged: {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
root.loadingChanged(loadRequest.status);
}
onWindowCloseRequested: {
root.destroy();
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
desktop.initWebviewProfileHandlers(webview.profile);
}
}
} // item
Keys.onPressed: {
switch(event.key) {
case Qt.Key_L:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
addressBar.selectAll()
addressBar.forceActiveFocus()
}
break;
}
}
} // dialog

View file

@ -0,0 +1,58 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebEngine 1.5
import controlsUit 1.0
WebView {
id: webview
url: "https://highfidelity.com/"
profile: FileTypeProfile;
property var parentRoot: null
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.Deferred
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
onFeaturePermissionRequested: {
if (feature == 2) { // QWebEnginePage::MediaAudioCapture
grantFeaturePermission(securityOrigin, feature, true);
} else {
permissionsBar.securityOrigin = securityOrigin;
permissionsBar.feature = feature;
parentRoot.showPermissionsBar();
}
}
onLoadingChanged: {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
parentRoot.loadingChanged(loadRequest.status);
}
onWindowCloseRequested: {
parentRoot.destroy();
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
desktop.initWebviewProfileHandlers(webview.profile);
}
}

View file

@ -1,50 +0,0 @@
//
// InfoView.qml
//
// Created by Bradley Austin Davis on 27 Apr 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
//
import QtQuick 2.5
import Hifi 1.0 as Hifi
import controlsUit 1.0
import "qrc:////qml//windows" as Windows
Windows.ScrollingWindow {
id: root
width: 800
height: 800
resizable: true
Hifi.InfoView {
id: infoView
width: pane.contentWidth
implicitHeight: pane.scrollHeight
WebView {
id: webview
objectName: "WebView"
anchors.fill: parent
url: infoView.url
}
}
Component.onCompleted: {
centerWindow(root);
}
onVisibleChanged: {
if (visible) {
centerWindow(root);
}
}
function centerWindow() {
desktop.centerOnVisible(root);
}
}

View file

@ -1,108 +0,0 @@
//
// QmlWebWindow.qml
//
// Created by Bradley Austin Davis on 17 Dec 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
//
import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import "qrc:////qml//windows" as Windows
import controlsUit 1.0 as Controls
import stylesUit 1.0
Windows.ScrollingWindow {
id: root
HifiConstants { id: hifi }
title: "WebWindow"
resizable: true
shown: false
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
destroyOnCloseButton: false
property alias source: webview.url
property alias scriptUrl: webview.userScriptUrl
// This is for JS/QML communication, which is unused in a WebWindow,
// but not having this here results in spurious warnings about a
// missing signal
signal sendToScript(var message);
signal moved(vector2d position);
signal resized(size size);
function notifyMoved() {
moved(Qt.vector2d(x, y));
}
function notifyResized() {
resized(Qt.size(width, height));
}
onXChanged: notifyMoved();
onYChanged: notifyMoved();
onWidthChanged: notifyResized();
onHeightChanged: notifyResized();
onShownChanged: {
keyboardEnabled = HMD.active;
}
Item {
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Controls.WebView {
id: webview
url: "about:blank"
anchors.fill: parent
focus: true
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
eventBridge.webEventReceived.connect(onWebEventReceived);
}
}
}
}

View file

@ -0,0 +1,53 @@
import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import controlsUit 1.0 as Controls
import stylesUit 1.0
Controls.WebView {
id: webview
url: "about:blank"
anchors.fill: parent
focus: true
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
eventBridge.webEventReceived.connect(onWebEventReceived);
}
}

View file

@ -1,14 +1,13 @@
import QtQuick 2.5
import controlsUit 1.0
import stylesUit 1.0
import "windows"
import "."
ScrollingWindow {
id: root
HifiConstants { id: hifi }
//HifiStyles.HifiConstants { id: hifistyles }
title: "Browser"
resizable: true
destroyOnHidden: true
@ -30,6 +29,7 @@ ScrollingWindow {
}
function setProfile(profile) {
webview.profile = profile;
}
function showPermissionsBar(){
@ -41,6 +41,7 @@ ScrollingWindow {
}
function allowPermissions(){
webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true);
hidePermissionsBar();
}
@ -198,10 +199,15 @@ ScrollingWindow {
}
}
ProxyWebView {
BrowserWebView {
id: webview
anchors.centerIn: parent
url: "https://highfidelity.com/"
parentRoot: root
anchors.top: buttons.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
} // item

View file

@ -0,0 +1,8 @@
import QtQuick 2.5
import controlsUit 1.0
ProxyWebView {
property var parentRoot: null
function grantFeaturePermission(origin, feature) {}
}

View file

@ -24,7 +24,7 @@ Windows.ScrollingWindow {
width: pane.contentWidth
implicitHeight: pane.scrollHeight
ProxyWebView {
BaseWebView {
id: webview
objectName: "WebView"
anchors.fill: parent

View file

@ -11,6 +11,7 @@
import QtQuick 2.5
import "windows" as Windows
import "."
import controlsUit 1.0 as Controls
import stylesUit 1.0
@ -55,12 +56,8 @@ Windows.ScrollingWindow {
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Controls.WebView {
QmlWebWindowView {
id: webview
url: "about:blank"
property string userScriptUrl: ""
anchors.fill: parent
focus: true
}
}
}

View file

@ -0,0 +1,5 @@
import QtQuick 2.5
import controlsUit 1.0
BaseWebView {
}

View file

@ -129,11 +129,11 @@ Item {
}
StatText {
visible: root.expanded
text: "Intersection calls: Entities/Overlays/Avatars/HUD\n " +
"Styluses:\t" + root.stylusPicksUpdated.x + "/" + root.stylusPicksUpdated.y + "/" + root.stylusPicksUpdated.z + "/" + root.stylusPicksUpdated.w + "\n " +
"Rays:\t" + root.rayPicksUpdated.x + "/" + root.rayPicksUpdated.y + "/" + root.rayPicksUpdated.z + "/" + root.rayPicksUpdated.w + "\n " +
"Parabolas:\t" + root.parabolaPicksUpdated.x + "/" + root.parabolaPicksUpdated.y + "/" + root.parabolaPicksUpdated.z + "/" + root.parabolaPicksUpdated.w + "\n " +
"Colliders:\t" + root.collisionPicksUpdated.x + "/" + root.collisionPicksUpdated.y + "/" + root.collisionPicksUpdated.z + "/" + root.collisionPicksUpdated.w
text: "Intersection calls: Entities/Avatars/HUD\n " +
"Styluses:\t" + root.stylusPicksUpdated.x + "/" + root.stylusPicksUpdated.y + "/" + root.stylusPicksUpdated.z + "\n " +
"Rays:\t" + root.rayPicksUpdated.x + "/" + root.rayPicksUpdated.y + "/" + root.rayPicksUpdated.z + "\n " +
"Parabolas:\t" + root.parabolaPicksUpdated.x + "/" + root.parabolaPicksUpdated.y + "/" + root.parabolaPicksUpdated.z + "\n " +
"Colliders:\t" + root.collisionPicksUpdated.x + "/" + root.collisionPicksUpdated.y + "/" + root.collisionPicksUpdated.z
}
}
}

View file

@ -1,5 +1,5 @@
//
// Web3DOverlay.qml
// Web3DSurface.qml
//
// Created by David Rowe on 16 Dec 2016.
// Copyright 2016 High Fidelity, Inc.

View file

@ -18,6 +18,7 @@ Rectangle {
property bool safeLoading: false
property bool loadingLatched: false
property bool loading: false
property var loadingRequest: null

View file

@ -42,6 +42,8 @@ Rectangle {
property var activeTab: "nearbyTab";
property bool currentlyEditingDisplayName: false
property bool punctuationMode: false;
property double loudSortTime: 0.0;
readonly property double kLOUD_SORT_PERIOD_MS: 1000.0;
HifiConstants { id: hifi; }
RootHttpRequest { id: http; }
@ -1247,6 +1249,11 @@ Rectangle {
}
}
}
if (nearbyTable.sortIndicatorColumn == 0 && Date.now() - pal.loudSortTime >= pal.kLOUD_SORT_PERIOD_MS) {
// Current sort by loudness so re-sort.
sortModel();
pal.loudSortTime = Date.now();
}
break;
case 'clearLocalQMLData':
ignored = {};

View file

@ -21,7 +21,7 @@ Rectangle {
HifiControlsUit.Keyboard {
id: keyboard
z: 1000
raised: parent.keyboardEnabled && parent.keyboardRaised
raised: parent.keyboardEnabled && parent.keyboardRaised && HMD.active
numeric: parent.punctuationMode
anchors {
left: parent.left

View file

@ -607,7 +607,7 @@ Rectangle {
} else if (msg.method === "showTrashLightbox") {
lightboxPopup.titleText = "Send \"" + msg.itemName + "\" to Trash";
lightboxPopup.bodyText = "Sending this item to the Trash means you will no longer own this item " +
"and it will be inaccessible to you from Purchases.\n\nThis action cannot be undone.";
"and it will be inaccessible to you from Inventory.\n\nThis action cannot be undone.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;

View file

@ -0,0 +1,7 @@
import QtQuick 2.0
import QtWebEngine 1.5
import "../../controls" as Controls
Controls.TabletWebView {
profile: WebEngineProfile { httpUserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"}
}

View file

@ -2,7 +2,6 @@ import QtQuick 2.0
import "../../controls" as Controls
Controls.TabletWebView {
profile: WebEngineProfile { httpUserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"}
}

View file

@ -20,7 +20,8 @@
*
* @hifi-interface
* @hifi-client-entity
*
* @hifi-avatar
*
* @property {string} buildDate
* @property {string} buildVersion
* @property {string} qtVersion

View file

@ -102,7 +102,7 @@
#include <MessagesClient.h>
#include <hfm/ModelFormatRegistry.h>
#include <model-networking/ModelCacheScriptingInterface.h>
#include <model-networking/TextureCacheScriptingInterface.h>
#include <material-networking/TextureCacheScriptingInterface.h>
#include <ModelEntityItem.h>
#include <NetworkAccessManager.h>
#include <NetworkingConstants.h>
@ -152,8 +152,9 @@
#include <trackers/EyeTracker.h>
#include <avatars-renderer/ScriptAvatar.h>
#include <RenderableEntityItem.h>
#include <RenderableTextEntityItem.h>
#include <RenderableWebEntityItem.h>
#include <model-networking/MaterialCache.h>
#include <material-networking/MaterialCache.h>
#include "recording/ClipCache.h"
#include "AudioClient.h"
@ -198,15 +199,12 @@
#include "ui/AvatarInputs.h"
#include "ui/DialogsManager.h"
#include "ui/LoginDialog.h"
#include "ui/overlays/Cube3DOverlay.h"
#include "ui/overlays/Web3DOverlay.h"
#include "ui/Snapshot.h"
#include "ui/SnapshotAnimated.h"
#include "ui/StandAloneJSConsole.h"
#include "ui/Stats.h"
#include "ui/AnimStats.h"
#include "ui/UpdateDialog.h"
#include "ui/overlays/Overlays.h"
#include "ui/DomainConnectionModel.h"
#include "ui/Keyboard.h"
#include "Util.h"
@ -351,6 +349,8 @@ static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";
static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
static const QString KEEP_ME_LOGGED_IN_SETTING_NAME = "keepMeLoggedIn";
static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
#if defined(Q_OS_ANDROID)
static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt";
#endif
@ -603,8 +603,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
__android_log_write(ANDROID_LOG_FATAL,"Interface",local);
abort();
}
#endif
#else
qApp->getLogger()->addMessage(qPrintable(logMessage));
#endif
}
}
@ -622,7 +623,7 @@ public:
case NestableType::Entity:
return getEntityModelProvider(static_cast<EntityItemID>(uuid));
case NestableType::Overlay:
return getOverlayModelProvider(static_cast<OverlayID>(uuid));
return nullptr;
case NestableType::Avatar:
return getAvatarModelProvider(uuid);
}
@ -646,22 +647,6 @@ private:
return provider;
}
scriptable::ModelProviderPointer getOverlayModelProvider(OverlayID overlayID) {
scriptable::ModelProviderPointer provider;
auto &overlays = qApp->getOverlays();
if (auto overlay = overlays.getOverlay(overlayID)) {
if (auto base3d = std::dynamic_pointer_cast<Base3DOverlay>(overlay)) {
provider = std::dynamic_pointer_cast<scriptable::ModelProvider>(base3d);
provider->modelProviderType = NestableType::Overlay;
} else {
qCWarning(interfaceapp) << "no renderer for overlay ID" << overlayID.toString();
}
} else {
qCWarning(interfaceapp) << "overlay not found" << overlayID.toString();
}
return provider;
}
scriptable::ModelProviderPointer getAvatarModelProvider(QUuid sessionUUID) {
scriptable::ModelProviderPointer provider;
auto avatarManager = DependencyManager::get<AvatarManager>();
@ -946,9 +931,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
// FIXME move to header, or better yet, design some kind of UI manager
// to take care of highlighting keyboard focused items, rather than
// continuing to overburden Application.cpp
std::shared_ptr<Cube3DOverlay> _keyboardFocusHighlight{ nullptr };
OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID };
QUuid _keyboardFocusHighlightID;
OffscreenGLCanvas* _qmlShareContext { nullptr };
@ -989,7 +972,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
QApplication(argc, argv),
_window(new MainWindow(desktop())),
_sessionRunTimer(startupTimer),
#ifndef Q_OS_ANDROID
_logger(new FileLogger(this)),
#endif
_previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)),
_entitySimulation(new PhysicalEntitySimulation()),
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
@ -1123,7 +1108,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
auto accountManager = DependencyManager::get<AccountManager>();
#ifndef Q_OS_ANDROID
_logger->setSessionID(accountManager->getSessionID());
#endif
setCrashAnnotation("metaverse_session_id", accountManager->getSessionID().toString().toStdString());
setCrashAnnotation("main_thread_id", std::to_string((size_t)QThread::currentThreadId()));
@ -1215,9 +1202,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (tabletScriptingInterface) {
tabletScriptingInterface->setQmlTabletRoot(SYSTEM_TABLET, nullptr);
}
getOverlays().deleteOverlay(getTabletScreenID());
getOverlays().deleteOverlay(getTabletHomeButtonID());
getOverlays().deleteOverlay(getTabletFrameID());
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
entityScriptingInterface->deleteEntity(getTabletScreenID());
entityScriptingInterface->deleteEntity(getTabletHomeButtonID());
entityScriptingInterface->deleteEntity(getTabletFrameID());
_failedToConnectToEntityServer = false;
});
@ -1307,10 +1295,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (isHMDMode()) {
emit loginDialogFocusDisabled();
dialogsManager->hideLoginDialog();
createLoginDialogOverlay();
createLoginDialog();
} else {
getOverlays().deleteOverlay(_loginDialogOverlayID);
_loginDialogOverlayID = OverlayID();
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_loginDialogID);
_loginDialogID = QUuid();
_loginStateManager.tearDown();
dialogsManager->showLoginDialog();
emit loginDialogFocusEnabled();
@ -1901,25 +1889,27 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
SpacemouseManager::getInstance().init();
#endif
// If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity,
[this](const EntityItemID& entityItemID, const PointerEvent& event) {
// If the user clicks on an object, we will check that it's a web surface, and if so, set the focus to it
auto pointerManager = DependencyManager::get<PointerManager>();
auto keyboardFocusOperator = [this](const QUuid& id, const PointerEvent& event) {
if (event.shouldFocus()) {
if (getEntities()->wantsKeyboardFocus(entityItemID)) {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
setKeyboardFocusEntity(entityItemID);
} else {
auto keyboard = DependencyManager::get<Keyboard>();
if (getEntities()->wantsKeyboardFocus(id)) {
setKeyboardFocusEntity(id);
} else if (!keyboard->containsID(id)) { // FIXME: this is a hack to make the keyboard work for now, since the keys would otherwise steal focus
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
}
}
});
};
connect(pointerManager.data(), &PointerManager::triggerBeginEntity, keyboardFocusOperator);
connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, keyboardFocusOperator);
connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [this](const EntityItemID& entityItemID) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityItemID) {
if (entityItemID == _keyboardFocusedEntity.get()) {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
}
});
}, Qt::QueuedConnection);
EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
if (_aboutToQuit) {
@ -1979,33 +1969,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return false;
});
EntityTree::setAddMaterialToOverlayOperator([this](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
auto overlay = _overlays.getOverlay(overlayID);
if (overlay) {
overlay->addMaterial(material, parentMaterialName);
return true;
EntityTree::setGetEntityObjectOperator([this](const QUuid& id) -> QObject* {
auto entities = getEntities();
if (auto entity = entities->renderableForEntityId(id)) {
return qobject_cast<QObject*>(entity.get());
}
return false;
});
EntityTree::setRemoveMaterialFromOverlayOperator([this](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
auto overlay = _overlays.getOverlay(overlayID);
if (overlay) {
overlay->removeMaterial(material, parentMaterialName);
return true;
}
return false;
return nullptr;
});
// Keyboard focus handling for Web overlays.
auto overlays = &(qApp->getOverlays());
connect(overlays, &Overlays::overlayDeleted, [this](const OverlayID& overlayID) {
if (overlayID == _keyboardFocusedOverlay.get()) {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
EntityTree::setTextSizeOperator([this](const QUuid& id, const QString& text) {
auto entities = getEntities();
if (auto entity = entities->renderableForEntityId(id)) {
if (auto renderable = std::dynamic_pointer_cast<render::entities::TextEntityRenderer>(entity)) {
return renderable->textSize(text);
}
}
return QSizeF(0.0f, 0.0f);
});
connect(this, &Application::aboutToQuit, [this]() {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
});
@ -2326,8 +2308,30 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
});
EntityTreeRenderer::setGetAvatarUpOperator([] {
return DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) {
if (billboardMode == BillboardMode::YAW) {
//rotate about vertical to face the camera
ViewFrustum frustum;
copyViewFrustum(frustum);
glm::vec3 dPosition = frustum.getPosition() - position;
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
} else if (billboardMode == BillboardMode::FULL) {
ViewFrustum frustum;
copyViewFrustum(frustum);
glm::vec3 cameraPos = frustum.getPosition();
// use the referencial from the avatar, y isn't always up
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
// check to see if glm::lookAt will work / using glm::lookAt variable name
glm::highp_vec3 s(glm::cross(position - cameraPos, avatarUP));
// make sure s is not NaN for any component
if (glm::length2(s) > 0.0f) {
return glm::conjugate(glm::toQuat(glm::lookAt(cameraPos, position, avatarUP)));
}
}
return rotation;
});
render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
@ -2353,7 +2357,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
});
});
auto rootItemLoadedFunctor = [webSurface, url, isTablet] {
Application::setupQmlSurface(webSurface->getSurfaceContext(), isTablet || url == OVERLAY_LOGIN_DIALOG.toString());
Application::setupQmlSurface(webSurface->getSurfaceContext(), isTablet || url == LOGIN_DIALOG.toString());
};
if (webSurface->getRootItem()) {
rootItemLoadedFunctor();
@ -2372,7 +2376,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Fix for crash in QtWebEngineCore when rapidly switching domains
// Call stop on the QWebEngineView before destroying OffscreenQMLSurface.
if (rootItem) {
if (rootItem && !cachedWebSurface) {
// stop loading
QMetaObject::invokeMethod(rootItem, "stop");
}
@ -2401,6 +2405,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
});
// Preload Tablet sounds
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(qApp->getEntities()->getTree());
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
DependencyManager::get<Keyboard>()->createKeyboard();
@ -2608,11 +2613,10 @@ void Application::cleanupBeforeQuit() {
_applicationStateDevice.reset();
{
if (_keyboardFocusHighlightID != UNKNOWN_OVERLAY_ID) {
getOverlays().deleteOverlay(_keyboardFocusHighlightID);
_keyboardFocusHighlightID = UNKNOWN_OVERLAY_ID;
if (_keyboardFocusHighlightID != UNKNOWN_ENTITY_ID) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_keyboardFocusHighlightID);
_keyboardFocusHighlightID = UNKNOWN_ENTITY_ID;
}
_keyboardFocusHighlight = nullptr;
}
{
@ -3116,7 +3120,7 @@ void Application::initializeUi() {
});
#if !defined(DISABLE_QML)
// Pre-create a couple of Web3D overlays to speed up tablet UI
// Pre-create a couple of offscreen surfaces to speed up tablet UI
auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
offscreenSurfaceCache->setOnRootContextCreated([&](const QString& rootObject, QQmlContext* surfaceContext) {
if (rootObject == TabletScriptingInterface::QML) {
@ -3837,8 +3841,8 @@ static inline bool isKeyEvent(QEvent::Type type) {
return type == QEvent::KeyPress || type == QEvent::KeyRelease;
}
bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) {
if (!_keyboardFocusedEntity.get().isInvalidID()) {
bool Application::handleKeyEventForFocusedEntity(QEvent* event) {
if (_keyboardFocusedEntity.get() != UNKNOWN_ENTITY_ID) {
switch (event->type()) {
case QEvent::KeyPress:
case QEvent::KeyRelease:
@ -3859,28 +3863,6 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) {
}
}
if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) {
switch (event->type()) {
case QEvent::KeyPress:
case QEvent::KeyRelease: {
// Only Web overlays can have focus.
auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get()));
if (overlay && overlay->getEventHandler()) {
event->setAccepted(false);
QCoreApplication::sendEvent(overlay->getEventHandler(), event);
if (event->isAccepted()) {
_lastAcceptedKeyPress = usecTimestampNow();
return true;
}
}
}
break;
default:
break;
}
}
return false;
}
@ -3923,8 +3905,8 @@ bool Application::event(QEvent* event) {
return false;
}
// Allow focused Entities and Overlays to handle keyboard input
if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event)) {
// Allow focused Entities to handle keyboard input
if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntity(event)) {
return true;
}
@ -4405,9 +4387,9 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
buttons, event->modifiers());
if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) {
getOverlays().mouseMoveEvent(&mappedEvent);
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_ENTITY_ID) {
getEntities()->mouseMoveEvent(&mappedEvent);
getOverlays().mouseMoveEvent(&mappedEvent);
}
_controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
@ -4439,15 +4421,16 @@ void Application::mousePressEvent(QMouseEvent* event) {
#else
QPointF transformedPos;
#endif
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
getOverlays().mousePressEvent(&mappedEvent);
QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers());
std::pair<float, QUuid> entityResult;
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
getEntities()->mousePressEvent(&mappedEvent);
entityResult = getEntities()->mousePressEvent(&mappedEvent);
}
std::pair<float, QUuid> overlayResult = getOverlays().mousePressEvent(&mappedEvent);
QUuid focusedEntity = entityResult.first < overlayResult.first ? entityResult.second : overlayResult.second;
setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(focusedEntity) ? focusedEntity : UNKNOWN_ENTITY_ID);
_controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
@ -4487,10 +4470,10 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) {
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
getOverlays().mouseDoublePressEvent(&mappedEvent);
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
getEntities()->mouseDoublePressEvent(&mappedEvent);
}
getOverlays().mouseDoublePressEvent(&mappedEvent);
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface->isMouseCaptured()) {
@ -4514,8 +4497,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
getOverlays().mouseReleaseEvent(&mappedEvent);
getEntities()->mouseReleaseEvent(&mappedEvent);
getOverlays().mouseReleaseEvent(&mappedEvent);
_controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
@ -4963,7 +4946,11 @@ void Application::idle() {
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
// details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing
// details normally.
#ifdef Q_OS_ANDROID
bool showWarnings = false;
#else
bool showWarnings = getLogger()->extraDebugging();
#endif
PerformanceWarning warn(showWarnings, "idle()");
{
@ -4977,31 +4964,19 @@ void Application::idle() {
update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS));
}
// Update focus highlight for entity or overlay.
{
if (!_keyboardFocusedEntity.get().isInvalidID() || _keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) {
{ // Update keyboard focus highlight
if (!_keyboardFocusedEntity.get().isInvalidID()) {
const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;
if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
} else {
// update position of highlight overlay
if (!_keyboardFocusedEntity.get().isInvalidID()) {
auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
if (entity && _keyboardFocusHighlight) {
_keyboardFocusHighlight->setWorldOrientation(entity->getWorldOrientation());
_keyboardFocusHighlight->setWorldPosition(entity->getWorldPosition());
}
} else {
// Only Web overlays can have focus.
auto overlay =
std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get()));
if (overlay && _keyboardFocusHighlight) {
_keyboardFocusHighlight->setWorldOrientation(overlay->getWorldOrientation());
_keyboardFocusHighlight->setWorldPosition(overlay->getWorldPosition());
}
if (auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get())) {
EntityItemProperties properties;
properties.setPosition(entity->getWorldPosition());
properties.setRotation(entity->getWorldOrientation());
properties.setDimensions(entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_keyboardFocusHighlightID, properties);
}
}
}
@ -5799,118 +5774,80 @@ void Application::rotationModeChanged() const {
}
void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions) {
// Create focus
if (qApp->getLoginDialogPoppedUp()) {
return;
}
if (_keyboardFocusHighlightID == UNKNOWN_OVERLAY_ID || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight = std::make_shared<Cube3DOverlay>();
_keyboardFocusHighlight->setAlpha(1.0f);
_keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });
_keyboardFocusHighlight->setIsSolid(false);
_keyboardFocusHighlight->setPulseMin(0.5);
_keyboardFocusHighlight->setPulseMax(1.0);
_keyboardFocusHighlight->setColorPulse(1.0);
_keyboardFocusHighlight->setIgnorePickIntersection(true);
_keyboardFocusHighlight->setDrawInFront(false);
_keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (_keyboardFocusHighlightID == UNKNOWN_ENTITY_ID || !entityScriptingInterface->isAddedEntity(_keyboardFocusHighlightID)) {
EntityItemProperties properties;
properties.setType(EntityTypes::Box);
properties.setAlpha(1.0f);
properties.setColor({ 0xFF, 0xEF, 0x00 });
properties.setPrimitiveMode(PrimitiveMode::LINES);
properties.getPulse().setMin(0.5);
properties.getPulse().setMax(1.0f);
properties.getPulse().setColorMode(PulseMode::IN_PHASE);
properties.setIgnorePickIntersection(true);
_keyboardFocusHighlightID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
}
// Position focus
_keyboardFocusHighlight->setWorldOrientation(rotation);
_keyboardFocusHighlight->setWorldPosition(position);
_keyboardFocusHighlight->setDimensions(dimensions);
_keyboardFocusHighlight->setVisible(true);
EntityItemProperties properties;
properties.setPosition(position);
properties.setRotation(rotation);
properties.setDimensions(dimensions);
properties.setVisible(true);
entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
}
QUuid Application::getKeyboardFocusEntity() const {
return _keyboardFocusedEntity.get();
}
static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
if (qApp->getLoginDialogPoppedUp()) {
return;
}
if (_keyboardFocusedEntity.get() != entityItemID) {
_keyboardFocusedEntity.set(entityItemID);
if (_keyboardFocusHighlight && _keyboardFocusedOverlay.get() == UNKNOWN_OVERLAY_ID) {
_keyboardFocusHighlight->setVisible(false);
}
if (entityItemID == UNKNOWN_ENTITY_ID) {
return;
}
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (!properties.getLocked() && properties.getVisible()) {
auto entities = getEntities();
auto entityId = _keyboardFocusedEntity.get();
if (entities->wantsKeyboardFocus(entityId)) {
entities->setProxyWindow(entityId, _window->windowHandle());
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_lastAcceptedKeyPress = usecTimestampNow();
auto entity = getEntities()->getEntity(entityId);
if (entity) {
setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
}
}
}
}
}
OverlayID Application::getKeyboardFocusOverlay() {
return _keyboardFocusedOverlay.get();
}
void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) {
if (overlayID != _keyboardFocusedOverlay.get()) {
if (qApp->getLoginDialogPoppedUp() && !_loginDialogOverlayID.isNull()) {
if (overlayID == _loginDialogOverlayID) {
void Application::setKeyboardFocusEntity(const QUuid& id) {
if (_keyboardFocusedEntity.get() != id) {
if (qApp->getLoginDialogPoppedUp() && !_loginDialogID.isNull()) {
if (id == _loginDialogID) {
emit loginDialogFocusEnabled();
} else {
// that's the only overlay we want in focus;
// that's the only entity we want in focus;
return;
}
}
_keyboardFocusedOverlay.set(overlayID);
_keyboardFocusedEntity.set(id);
if (_keyboardFocusHighlight && _keyboardFocusedEntity.get() == UNKNOWN_ENTITY_ID) {
_keyboardFocusHighlight->setVisible(false);
}
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (id != UNKNOWN_ENTITY_ID) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_VISIBLE;
desiredProperties += PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT;
auto properties = entityScriptingInterface->getEntityProperties(id);
if (properties.getVisible()) {
auto entities = getEntities();
auto entityId = _keyboardFocusedEntity.get();
if (entities->wantsKeyboardFocus(entityId)) {
entities->setProxyWindow(entityId, _window->windowHandle());
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_lastAcceptedKeyPress = usecTimestampNow();
if (overlayID == UNKNOWN_OVERLAY_ID) {
return;
}
auto overlayType = getOverlays().getOverlayType(overlayID);
auto isVisible = getOverlays().getProperty(overlayID, "visible").value.toBool();
if (overlayType == Web3DOverlay::TYPE && isVisible) {
auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(overlayID));
overlay->setProxyWindow(_window->windowHandle());
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_lastAcceptedKeyPress = usecTimestampNow();
if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) {
auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR;
const float OVERLAY_DEPTH = 0.0105f;
setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH));
} else if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
if (properties.getShowKeyboardFocusHighlight()) {
if (auto entity = entities->getEntity(entityId)) {
setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
return;
}
}
}
}
}
EntityItemProperties properties;
properties.setVisible(false);
entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
}
}
@ -6287,6 +6224,19 @@ void Application::update(float deltaTime) {
auto grabManager = DependencyManager::get<GrabManager>();
grabManager->simulateGrabs();
// TODO: break these out into distinct perfTimers when they prove interesting
{
PROFILE_RANGE(app, "PickManager");
PerformanceTimer perfTimer("pickManager");
DependencyManager::get<PickManager>()->update();
}
{
PROFILE_RANGE(app, "PointerManager");
PerformanceTimer perfTimer("pointerManager");
DependencyManager::get<PointerManager>()->update();
}
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
{
@ -6300,40 +6250,57 @@ void Application::update(float deltaTime) {
PROFILE_RANGE(simulation_physics, "PrePhysics");
PerformanceTimer perfTimer("prePhysics)");
{
PROFILE_RANGE(simulation_physics, "RemoveEntities");
const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics();
_physicsEngine->removeObjects(motionStates);
{
PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
_physicsEngine->removeObjects(motionStates);
}
_entitySimulation->deleteObjectsRemovedFromPhysics();
}
VectorOfMotionStates motionStates;
getEntities()->getTree()->withReadLock([&] {
_entitySimulation->getObjectsToAddToPhysics(motionStates);
_physicsEngine->addObjects(motionStates);
});
getEntities()->getTree()->withReadLock([&] {
_entitySimulation->getObjectsToChange(motionStates);
VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
_entitySimulation->setObjectsToChange(stillNeedChange);
});
{
PROFILE_RANGE(simulation_physics, "AddEntities");
VectorOfMotionStates motionStates;
getEntities()->getTree()->withReadLock([&] {
_entitySimulation->getObjectsToAddToPhysics(motionStates);
PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
_physicsEngine->addObjects(motionStates);
});
}
{
VectorOfMotionStates motionStates;
PROFILE_RANGE(simulation_physics, "ChangeEntities");
getEntities()->getTree()->withReadLock([&] {
_entitySimulation->getObjectsToChange(motionStates);
VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
_entitySimulation->setObjectsToChange(stillNeedChange);
});
}
_entitySimulation->applyDynamicChanges();
t1 = std::chrono::high_resolution_clock::now();
PhysicsEngine::Transaction transaction;
avatarManager->buildPhysicsTransaction(transaction);
_physicsEngine->processTransaction(transaction);
avatarManager->handleProcessedPhysicsTransaction(transaction);
myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
_physicsEngine->processTransaction(transaction);
myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction);
myAvatar->prepareForPhysicsSimulation();
_physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying());
{
PROFILE_RANGE(simulation_physics, "Avatars");
PhysicsEngine::Transaction transaction;
avatarManager->buildPhysicsTransaction(transaction);
_physicsEngine->processTransaction(transaction);
avatarManager->handleProcessedPhysicsTransaction(transaction);
myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
_physicsEngine->processTransaction(transaction);
myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction);
myAvatar->prepareForPhysicsSimulation();
_physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying());
}
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
dynamic->prepareForPhysicsSimulation();
});
{
PROFILE_RANGE(simulation_physics, "PrepareActions");
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
dynamic->prepareForPhysicsSimulation();
});
}
}
auto t2 = std::chrono::high_resolution_clock::now();
{
@ -6436,22 +6403,9 @@ void Application::update(float deltaTime) {
updateLOD(deltaTime);
if (!_loginDialogOverlayID.isNull()) {
_loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogOverlayID);
updateLoginDialogOverlayPosition();
}
// TODO: break these out into distinct perfTimers when they prove interesting
{
PROFILE_RANGE(app, "PickManager");
PerformanceTimer perfTimer("pickManager");
DependencyManager::get<PickManager>()->update();
}
{
PROFILE_RANGE(app, "PointerManager");
PerformanceTimer perfTimer("pointerManager");
DependencyManager::get<PointerManager>()->update();
if (!_loginDialogID.isNull()) {
_loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogID);
updateLoginDialogPosition();
}
{
@ -7217,7 +7171,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
scriptEngine->registerGlobalObject("Overlays", &_overlays);
qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue,
RayToOverlayIntersectionResultFromScriptValue);
@ -7334,8 +7287,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
registerInteractiveWindowMetaType(scriptEngine.data());
auto pickScriptingInterface = DependencyManager::get<PickScriptingInterface>();
@ -8306,7 +8257,7 @@ void Application::toggleLogDialog() {
bool keepOnTop =_keepLogWindowOnTop.get();
#ifdef Q_OS_WIN
_logDialog = new LogDialog(keepOnTop ? qApp->getWindow() : nullptr, getLogger());
#else
#elif !defined(Q_OS_ANDROID)
_logDialog = new LogDialog(nullptr, getLogger());
if (keepOnTop) {
@ -8857,45 +8808,47 @@ void Application::setShowBulletConstraintLimits(bool value) {
_physicsEngine->setShowBulletConstraintLimits(value);
}
void Application::createLoginDialogOverlay() {
const glm::vec2 LOGIN_OVERLAY_DIMENSIONS{ 0.89f, 0.5f };
const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f);
void Application::createLoginDialog() {
const glm::vec3 LOGIN_DIMENSIONS { 0.89f, 0.5f, 0.01f };
const auto OFFSET = glm::vec2(0.7f, -0.1f);
auto cameraPosition = _myCamera.getPosition();
auto cameraOrientation = _myCamera.getOrientation();
auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
auto headLookVec = (cameraOrientation * Vectors::FRONT);
// DEFAULT_DPI / tablet scale percentage
const float OVERLAY_DPI = 31.0f / (75.0f / 100.0f);
auto offset = headLookVec * OVERLAY_OFFSET.x;
auto overlayPosition = (cameraPosition + offset) + (upVec * OVERLAY_OFFSET.y);
QVariantMap overlayProperties = {
{ "name", "LoginDialogOverlay" },
{ "url", OVERLAY_LOGIN_DIALOG },
{ "position", vec3toVariant(overlayPosition) },
{ "orientation", quatToVariant(cameraOrientation) },
{ "isSolid", true },
{ "grabbable", false },
{ "ignorePickIntersection", false },
{ "alpha", 1.0 },
{ "dimensions", vec2ToVariant(LOGIN_OVERLAY_DIMENSIONS)},
{ "dpi", OVERLAY_DPI },
{ "visible", true }
};
auto& overlays = getOverlays();
_loginDialogOverlayID = overlays.addOverlay("web3d", overlayProperties);
auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID));
const float DPI = 31.0f / (75.0f / 100.0f);
auto offset = headLookVec * OFFSET.x;
auto position = (cameraPosition + offset) + (upVec * OFFSET.y);
EntityItemProperties properties;
properties.setType(EntityTypes::Web);
properties.setName("LoginDialogEntity");
properties.setSourceUrl(LOGIN_DIALOG.toString());
properties.setPosition(position);
properties.setRotation(cameraOrientation);
properties.setDimensions(LOGIN_DIMENSIONS);
properties.setPrimitiveMode(PrimitiveMode::SOLID);
properties.getGrab().setGrabbable(false);
properties.setIgnorePickIntersection(false);
properties.setAlpha(1.0f);
properties.setDPI(DPI);
properties.setVisible(true);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
_loginDialogID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
auto keyboard = DependencyManager::get<Keyboard>().data();
if (!keyboard->getAnchorID().isNull() && !_loginDialogOverlayID.isNull()) {
const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
if (!keyboard->getAnchorID().isNull() && !_loginDialogID.isNull()) {
auto keyboardLocalOffset = cameraOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
QVariantMap properties {
{ "position", vec3toVariant(overlayPosition + keyboardLocalOffset) },
{ "orientation", quatToVariant(cameraOrientation * KEYBOARD_LOCAL_ORIENTATION) },
};
overlays.editOverlay(keyboard->getAnchorID(), properties);
EntityItemProperties properties;
properties.setPosition(position + keyboardLocalOffset);
properties.setRotation(cameraOrientation * Quaternions::Y_180);
entityScriptingInterface->editEntity(keyboard->getAnchorID(), properties);
keyboard->setResetKeyboardPositionOnRaise(false);
}
setKeyboardFocusOverlay(_loginDialogOverlayID);
setKeyboardFocusEntity(_loginDialogID);
emit loginDialogFocusEnabled();
getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(false);
getApplicationCompositor().getReticleInterface()->setVisible(false);
@ -8904,38 +8857,43 @@ void Application::createLoginDialogOverlay() {
}
}
void Application::updateLoginDialogOverlayPosition() {
void Application::updateLoginDialogPosition() {
const float LOOK_AWAY_THRESHOLD_ANGLE = 70.0f;
const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f);
auto& overlays = getOverlays();
auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID));
auto overlayPositionVec = loginOverlay->getWorldPosition();
const auto OFFSET = glm::vec2(0.7f, -0.1f);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
auto properties = entityScriptingInterface->getEntityProperties(_loginDialogID, desiredProperties);
auto positionVec = properties.getPosition();
auto cameraPositionVec = _myCamera.getPosition();
auto cameraOrientation = cancelOutRollAndPitch(_myCamera.getOrientation());
auto headLookVec = (cameraOrientation * Vectors::FRONT);
auto overlayToHeadVec = overlayPositionVec - cameraPositionVec;
auto pointAngle = (glm::acos(glm::dot(glm::normalize(overlayToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
auto entityToHeadVec = positionVec - cameraPositionVec;
auto pointAngle = (glm::acos(glm::dot(glm::normalize(entityToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
auto offset = headLookVec * OVERLAY_OFFSET.x;
auto newOverlayPositionVec = (cameraPositionVec + offset) + (upVec * OVERLAY_OFFSET.y);
auto newOverlayOrientation = glm::inverse(glm::quat_cast(glm::lookAt(newOverlayPositionVec, cameraPositionVec, upVec))) * Quaternions::Y_180;
auto offset = headLookVec * OFFSET.x;
auto newPositionVec = (cameraPositionVec + offset) + (upVec * OFFSET.y);
bool overlayOutOfBounds = glm::distance(overlayPositionVec, cameraPositionVec) > 1.0f;
bool outOfBounds = glm::distance(positionVec, cameraPositionVec) > 1.0f;
if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || overlayOutOfBounds) {
QVariantMap properties {
{"position", vec3toVariant(newOverlayPositionVec)},
{"orientation", quatToVariant(newOverlayOrientation)}
};
overlays.editOverlay(_loginDialogOverlayID, properties);
const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
auto keyboardLocalOffset = newOverlayOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
QVariantMap keyboardProperties {
{ "position", vec3toVariant(newOverlayPositionVec + keyboardLocalOffset) },
{ "orientation", quatToVariant(newOverlayOrientation * KEYBOARD_LOCAL_ORIENTATION) },
};
auto keyboard = DependencyManager::get<Keyboard>().data();
overlays.editOverlay(keyboard->getAnchorID(), keyboardProperties);
if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || outOfBounds) {
{
EntityItemProperties properties;
properties.setPosition(newPositionVec);
properties.setRotation(cameraOrientation);
entityScriptingInterface->editEntity(_loginDialogID, properties);
}
{
glm::vec3 keyboardLocalOffset = cameraOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
glm::quat keyboardOrientation = cameraOrientation * glm::quat(glm::radians(glm::vec3(-30.0f, 180.0f, 0.0f)));
EntityItemProperties properties;
properties.setPosition(newPositionVec + keyboardLocalOffset);
properties.setRotation(keyboardOrientation);
entityScriptingInterface->editEntity(DependencyManager::get<Keyboard>()->getAnchorID(), properties);
}
}
}
@ -8952,10 +8910,9 @@ void Application::onDismissedLoginDialog() {
loginDialogPoppedUp.set(false);
auto keyboard = DependencyManager::get<Keyboard>().data();
keyboard->setResetKeyboardPositionOnRaise(true);
if (!_loginDialogOverlayID.isNull()) {
// deleting overlay.
getOverlays().deleteOverlay(_loginDialogOverlayID);
_loginDialogOverlayID = OverlayID();
if (!_loginDialogID.isNull()) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_loginDialogID);
_loginDialogID = QUuid();
_loginStateManager.tearDown();
}
resumeAfterLoginDialogActionTaken();
@ -9121,12 +9078,12 @@ void Application::updateSystemTabletMode() {
}
}
OverlayID Application::getTabletScreenID() const {
QUuid Application::getTabletScreenID() const {
auto HMD = DependencyManager::get<HMDScriptingInterface>();
return HMD->getCurrentTabletScreenID();
}
OverlayID Application::getTabletHomeButtonID() const {
QUuid Application::getTabletHomeButtonID() const {
auto HMD = DependencyManager::get<HMDScriptingInterface>();
return HMD->getCurrentHomeButtonID();
}
@ -9137,7 +9094,7 @@ QUuid Application::getTabletFrameID() const {
}
QVector<QUuid> Application::getTabletIDs() const {
// Most important overlays first.
// Most important first.
QVector<QUuid> result;
auto HMD = DependencyManager::get<HMDScriptingInterface>();
result << HMD->getCurrentTabletScreenID();

View file

@ -251,7 +251,9 @@ public:
void setActiveDisplayPlugin(const QString& pluginName);
#ifndef Q_OS_ANDROID
FileLogger* getLogger() const { return _logger; }
#endif
float getRenderResolutionScale() const;
@ -299,10 +301,10 @@ public:
void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));
OverlayID getTabletScreenID() const;
OverlayID getTabletHomeButtonID() const;
QUuid getTabletFrameID() const; // may be an entity or an overlay
QVector<QUuid> getTabletIDs() const; // In order of most important IDs first.
QUuid getTabletScreenID() const;
QUuid getTabletHomeButtonID() const;
QUuid getTabletFrameID() const;
QVector<QUuid> getTabletIDs() const;
void setAvatarOverrideUrl(const QUrl& url, bool save);
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
@ -325,8 +327,8 @@ public:
void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); }
bool getLoginDialogPoppedUp() const { return _loginDialogPoppedUp; }
void createLoginDialogOverlay();
void updateLoginDialogOverlayPosition();
void createLoginDialog();
void updateLoginDialogPosition();
// Check if a headset is connected
bool hasRiftControllers();
@ -440,10 +442,7 @@ public slots:
void setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions);
QUuid getKeyboardFocusEntity() const; // thread-safe
void setKeyboardFocusEntity(const EntityItemID& entityItemID);
OverlayID getKeyboardFocusOverlay();
void setKeyboardFocusOverlay(const OverlayID& overlayID);
void setKeyboardFocusEntity(const QUuid& id);
void addAssetToWorldMessageClose();
@ -534,7 +533,7 @@ private:
void init();
void pauseUntilLoginDetermined();
void resumeAfterLoginDialogActionTaken();
bool handleKeyEventForFocusedEntityOrOverlay(QEvent* event);
bool handleKeyEventForFocusedEntity(QEvent* event);
bool handleFileOpenEvent(QFileOpenEvent* event);
void cleanupBeforeQuit();
@ -599,7 +598,9 @@ private:
bool _aboutToQuit { false };
#ifndef Q_OS_ANDROID
FileLogger* _logger { nullptr };
#endif
bool _previousSessionCrashed;
@ -706,7 +707,7 @@ private:
QString _previousAvatarSkeletonModel;
float _previousAvatarTargetScale;
CameraMode _previousCameraMode;
OverlayID _loginDialogOverlayID;
QUuid _loginDialogID;
LoginStateManager _loginStateManager;
quint64 _lastFaceTrackerUpdate;
@ -724,7 +725,6 @@ private:
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();
ThreadSafeValueCache<EntityItemID> _keyboardFocusedEntity;
ThreadSafeValueCache<OverlayID> _keyboardFocusedOverlay;
quint64 _lastAcceptedKeyPress = 0;
bool _isForeground = true; // starts out assumed to be in foreground
bool _isGLInitialized { false };

View file

@ -21,6 +21,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
*/

View file

@ -50,15 +50,6 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& s
return avatarManager->getMyAvatar();
}
// search overlays
auto& overlays = qApp->getOverlays();
auto overlay = overlays.getOverlay(parentID);
parent = std::dynamic_pointer_cast<SpatiallyNestable>(overlay); // this will return nullptr for non-3d overlays
if (!parent.expired()) {
success = true;
return parent;
}
success = false;
return parent;
}

View file

@ -36,6 +36,7 @@ class AABox;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} presentTime <em>Read-only.</em>
* @property {number} engineRunTime <em>Read-only.</em>

View file

@ -21,6 +21,7 @@
*
* @hifi-client-entity
* @hifi-interface
* @hifi-avatar
*/
class LocationBookmarks : public Bookmarks, public Dependency {

View file

@ -170,7 +170,7 @@ void LoginStateManager::setUp() {
const unsigned int leftHand = 0;
QVariantMap leftPointerProperties {
{ "joint", "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND" },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "triggers", leftPointerTriggerProperties },
{ "posOffset", vec3toVariant(grabPointSphereOffsetLeft + malletOffset) },
{ "hover", true },
@ -197,7 +197,7 @@ void LoginStateManager::setUp() {
rightPointerTriggerProperties = QList<QVariant>({rtClick1, rtClick2});
QVariantMap rightPointerProperties{
{ "joint", "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "triggers", rightPointerTriggerProperties },
{ "posOffset", vec3toVariant(grabPointSphereOffsetRight + malletOffset) },
{ "hover", true },
@ -212,7 +212,7 @@ void LoginStateManager::setUp() {
pointers->enablePointer(_rightLoginPointerID);
}
void LoginStateManager::update(const QString dominantHand, const QUuid loginOverlayID) {
void LoginStateManager::update(const QString& dominantHand, const QUuid& loginEntityID) {
if (!isSetUp()) {
return;
}
@ -224,8 +224,8 @@ void LoginStateManager::update(const QString dominantHand, const QUuid loginOver
if (pointers && raypicks) {
const auto rightObjectID = raypicks->getPrevRayPickResult(_rightLoginPointerID)["objectID"].toUuid();
const auto leftObjectID = raypicks->getPrevRayPickResult(_leftLoginPointerID)["objectID"].toUuid();
const QString leftMode = (leftObjectID.isNull() || leftObjectID != loginOverlayID) ? "" : "full";
const QString rightMode = (rightObjectID.isNull() || rightObjectID != loginOverlayID) ? "" : "full";
const QString leftMode = (leftObjectID.isNull() || leftObjectID != loginEntityID) ? "" : "full";
const QString rightMode = (rightObjectID.isNull() || rightObjectID != loginEntityID) ? "" : "full";
pointers->setRenderState(_leftLoginPointerID, leftMode);
pointers->setRenderState(_rightLoginPointerID, rightMode);
if (_dominantHand == "left" && !leftObjectID.isNull()) {

View file

@ -26,7 +26,7 @@ public:
void setUp();
void tearDown();
void update(const QString dominantHand, const QUuid loginOverlayID);
void update(const QString& dominantHand, const QUuid& loginObjectID);
bool isSetUp() const { return (_leftLoginPointerID > PointerEvent::INVALID_POINTER_ID) && (_rightLoginPointerID > PointerEvent::INVALID_POINTER_ID); }

View file

@ -27,6 +27,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class SpeechRecognizer : public QObject, public Dependency {
Q_OBJECT

View file

@ -31,6 +31,7 @@ class AudioScope : public QObject, public Dependency {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} scopeInput <em>Read-only.</em>
* @property {number} scopeOutputLeft <em>Read-only.</em>

View file

@ -569,7 +569,7 @@ void AvatarActionHold::lateAvatarUpdate(const AnimPose& prePhysicsRoomPose, cons
}
btTransform worldTrans = rigidBody->getWorldTransform();
AnimPose worldBodyPose(1.0f, bulletToGLM(worldTrans.getRotation()), bulletToGLM(worldTrans.getOrigin()));
AnimPose worldBodyPose(glm::vec3(1), bulletToGLM(worldTrans.getRotation()), bulletToGLM(worldTrans.getOrigin()));
// transform the body transform into sensor space with the prePhysics sensor-to-world matrix.
// then transform it back into world uisng the postAvatarUpdate sensor-to-world matrix.

View file

@ -46,6 +46,7 @@ using SortedAvatar = std::pair<float, std::shared_ptr<Avatar>>;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @borrows AvatarList.getAvatarIdentifiers as getAvatarIdentifiers
* @borrows AvatarList.getAvatarsInRange as getAvatarsInRange

View file

@ -2980,7 +2980,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
auto animSkeleton = _skeletonModel->getRig().getAnimSkeleton();
// the rig is in the skeletonModel frame
AnimPose xform(1.0f, _skeletonModel->getRotation(), _skeletonModel->getTranslation());
AnimPose xform(glm::vec3(1), _skeletonModel->getRotation(), _skeletonModel->getTranslation());
if (_enableDebugDrawDefaultPose && animSkeleton) {
glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f);
@ -3025,7 +3025,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
updateHoldActions(_prePhysicsRoomPose, postUpdateRoomPose);
if (_enableDebugDrawDetailedCollision) {
AnimPose rigToWorldPose(1.0f, getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
AnimPose rigToWorldPose(glm::vec3(1.0f), getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
const int NUM_DEBUG_COLORS = 8;
const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = {
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f),
@ -4821,7 +4821,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
swingTwistDecomposition(hipsinWorldSpace, avatarUpWorld, resultingSwingInWorld, resultingTwistInWorld);
// remove scale present from sensorToWorldMatrix
followWorldPose.scale() = 1.0f;
followWorldPose.scale() = glm::vec3(1.0f);
if (isActive(Rotation)) {
//use the hmd reading for the hips follow
@ -5313,3 +5313,15 @@ void MyAvatar::releaseGrab(const QUuid& grabID) {
}
}
void MyAvatar::sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const {
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
if (entityTree) {
entityTree->withWriteLock([&] {
// force an update packet
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entityID, properties);
});
}
}

View file

@ -66,6 +66,7 @@ class MyAvatar : public Avatar {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Vec3} qmlPosition - A synonym for <code>position</code> for use by QML.
* @property {boolean} shouldRenderLocally=true - If <code>true</code> then your avatar is rendered for you in Interface,
@ -137,7 +138,7 @@ class MyAvatar : public Avatar {
* your avatar when rolling your HMD in degrees per second.
* @property {number} userHeight=1.75 - The height of the user in sensor space.
* @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. <em>Read-only.</em>
* @property {Uuid} SELF_ID - UUID representing "my avatar". Only use for local-only entities and overlays in situations
* @property {Uuid} SELF_ID - UUID representing "my avatar". Only use for local-only entities in situations
* where MyAvatar.sessionUUID is not available (e.g., if not connected to a domain). Note: Likely to be deprecated.
* <em>Read-only.</em>
* @property {number} walkSpeed
@ -1883,6 +1884,7 @@ private:
bool didTeleport();
bool getIsAway() const { return _isAway; }
void setAway(bool value);
void sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const override;
std::mutex _pinnedJointsMutex;
std::vector<int> _pinnedJoints;

View file

@ -41,7 +41,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
if (myAvatar->isJointPinned(hipsIndex)) {
Transform avatarTransform = myAvatar->getTransform();
AnimPose result = AnimPose(worldToSensorMat * avatarTransform.getMatrix() * Matrices::Y_180);
result.scale() = 1.0f;
result.scale() = glm::vec3(1.0f, 1.0f, 1.0f);
return result;
}
@ -108,7 +108,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
Rig::ControllerParameters params;
AnimPose avatarToRigPose(1.0f, Quaternions::Y_180, glm::vec3(0.0f));
AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
glm::mat4 rigToAvatarMatrix = Matrices::Y_180;
glm::mat4 avatarToWorldMatrix = createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition());
@ -127,7 +127,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
// preMult 180 is necessary to convert from avatar to rig coordinates.
// postMult 180 is necessary to convert head from -z forward to z forward.
glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(1.0f, headRot, glm::vec3(0.0f));
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
params.primaryControllerFlags[Rig::PrimaryControllerType_Head] = 0;
}

View file

@ -55,44 +55,47 @@ OtherAvatar::~OtherAvatar() {
void OtherAvatar::removeOrb() {
if (!_otherAvatarOrbMeshPlaceholderID.isNull()) {
qApp->getOverlays().deleteOverlay(_otherAvatarOrbMeshPlaceholderID);
_otherAvatarOrbMeshPlaceholderID = UNKNOWN_OVERLAY_ID;
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_otherAvatarOrbMeshPlaceholderID);
_otherAvatarOrbMeshPlaceholderID = UNKNOWN_ENTITY_ID;
}
}
void OtherAvatar::updateOrbPosition() {
if (_otherAvatarOrbMeshPlaceholder != nullptr) {
_otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition());
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
_otherAvatarOrbMeshPlaceholderID = qApp->getOverlays().addOverlay(_otherAvatarOrbMeshPlaceholder);
}
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
EntityItemProperties properties;
properties.setPosition(getHead()->getPosition());
DependencyManager::get<EntityScriptingInterface>()->editEntity(_otherAvatarOrbMeshPlaceholderID, properties);
}
}
void OtherAvatar::createOrb() {
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
_otherAvatarOrbMeshPlaceholder->setColor(getLoadingOrbColor(_loadingStatus));
_otherAvatarOrbMeshPlaceholder->setIsSolid(false);
_otherAvatarOrbMeshPlaceholder->setPulseMin(0.5);
_otherAvatarOrbMeshPlaceholder->setPulseMax(1.0);
_otherAvatarOrbMeshPlaceholder->setColorPulse(1.0);
_otherAvatarOrbMeshPlaceholder->setIgnorePickIntersection(true);
_otherAvatarOrbMeshPlaceholder->setDrawInFront(false);
_otherAvatarOrbMeshPlaceholderID = qApp->getOverlays().addOverlay(_otherAvatarOrbMeshPlaceholder);
// Position focus
_otherAvatarOrbMeshPlaceholder->setWorldOrientation(glm::quat(0.0f, 0.0f, 0.0f, 1.0));
_otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition());
_otherAvatarOrbMeshPlaceholder->setDimensions(glm::vec3(0.5f, 0.5f, 0.5f));
_otherAvatarOrbMeshPlaceholder->setVisible(true);
EntityItemProperties properties;
properties.setType(EntityTypes::Sphere);
properties.setAlpha(1.0f);
properties.setColor(getLoadingOrbColor(_loadingStatus));
properties.setPrimitiveMode(PrimitiveMode::LINES);
properties.getPulse().setMin(0.5f);
properties.getPulse().setMax(1.0f);
properties.getPulse().setColorMode(PulseMode::IN_PHASE);
properties.setIgnorePickIntersection(true);
properties.setPosition(getHead()->getPosition());
properties.setRotation(glm::quat(0.0f, 0.0f, 0.0f, 1.0));
properties.setDimensions(glm::vec3(0.5f, 0.5f, 0.5f));
properties.setVisible(true);
_otherAvatarOrbMeshPlaceholderID = DependencyManager::get<EntityScriptingInterface>()->addEntityInternal(properties, entity::HostType::LOCAL);
}
}
void OtherAvatar::indicateLoadingStatus(LoadingStatus loadingStatus) {
Avatar::indicateLoadingStatus(loadingStatus);
if (_otherAvatarOrbMeshPlaceholder) {
_otherAvatarOrbMeshPlaceholder->setColor(getLoadingOrbColor(_loadingStatus));
if (_otherAvatarOrbMeshPlaceholderID != UNKNOWN_ENTITY_ID) {
EntityItemProperties properties;
properties.setColor(getLoadingOrbColor(_loadingStatus));
DependencyManager::get<EntityScriptingInterface>()->editEntity(_otherAvatarOrbMeshPlaceholderID, properties);
}
}
@ -447,6 +450,10 @@ void OtherAvatar::handleChangedAvatarEntityData() {
EntityItemProperties properties;
int32_t bytesLeftToRead = data.size();
unsigned char* dataAt = (unsigned char*)(data.data());
// FIXME: This function will cause unintented changes in SpaillyNestable
// E.g overriding the ID index of an exisiting entity to temporary entity
// in the following map QHash<QUuid, SpatiallyNestableWeakPointer> _children;
// Andrew Meadows will address this issue
if (!properties.constructFromBuffer(dataAt, bytesLeftToRead)) {
// properties are corrupt
continue;
@ -489,6 +496,17 @@ void OtherAvatar::handleChangedAvatarEntityData() {
bool success = true;
if (entity) {
QUuid oldParentID = entity->getParentID();
// Since has overwrtiiten the back pointer
// from the parent children map (see comment for function call above),
// we need to for reset the back pointer in the map correctly by setting the parentID, but
// since the parentID of the entity has not changed we first need to set it some ither ID,
// then set the the original ID for the changes to take effect
// TODO: This is a horrible hack and once properties.constructFromBuffer no longer causes
// side effects...remove the following three lines
const QUuid NULL_ID = QUuid("{00000000-0000-0000-0000-000000000005}");
entity->setParentID(NULL_ID);
entity->setParentID(oldParentID);
if (entityTree->updateEntity(entityID, properties)) {
entity->updateLastEditedFromRemote();
} else {
@ -510,6 +528,11 @@ void OtherAvatar::handleChangedAvatarEntityData() {
}
}
stateItr.value().success = success;
if (success) {
stateItr.value().hash = newHash;
} else {
stateItr.value().hash = 0;
}
}
AvatarEntityIDs recentlyRemovedAvatarEntities = getAndClearRecentlyRemovedIDs();

View file

@ -16,8 +16,6 @@
#include <workload/Space.h>
#include "InterfaceLogging.h"
#include "ui/overlays/Overlays.h"
#include "ui/overlays/Sphere3DOverlay.h"
class AvatarManager;
class AvatarMotionState;
@ -76,9 +74,18 @@ protected:
void onAddAttachedAvatarEntity(const QUuid& id);
void onRemoveAttachedAvatarEntity(const QUuid& id);
class AvatarEntityDataHash {
public:
AvatarEntityDataHash(uint32_t h) : hash(h) {};
uint32_t hash { 0 };
bool success { false };
};
using MapOfAvatarEntityDataHashes = QMap<QUuid, AvatarEntityDataHash>;
MapOfAvatarEntityDataHashes _avatarEntityDataHashes;
std::vector<QUuid> _attachedAvatarEntities;
std::shared_ptr<Sphere3DOverlay> _otherAvatarOrbMeshPlaceholder { nullptr };
OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID };
QUuid _otherAvatarOrbMeshPlaceholderID;
AvatarMotionState* _motionState { nullptr };
std::vector<DetailedMotionState*> _detailedMotionStates;
int32_t _spaceIndex { -1 };

View file

@ -194,7 +194,6 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui
_calibrationCount(0),
_calibrationValues(),
_calibrationBillboard(NULL),
_calibrationBillboardID(UNKNOWN_OVERLAY_ID),
_calibrationMessage(QString()),
_isCalibrated(false)
{
@ -616,10 +615,6 @@ void DdeFaceTracker::setEyeClosingThreshold(float eyeClosingThreshold) {
static const int CALIBRATION_BILLBOARD_WIDTH = 300;
static const int CALIBRATION_BILLBOARD_HEIGHT = 120;
static const int CALIBRATION_BILLBOARD_TOP_MARGIN = 30;
static const int CALIBRATION_BILLBOARD_LEFT_MARGIN = 30;
static const int CALIBRATION_BILLBOARD_FONT_SIZE = 16;
static const float CALIBRATION_BILLBOARD_ALPHA = 0.5f;
static QString CALIBRATION_INSTRUCTION_MESSAGE = "Hold still to calibrate camera";
void DdeFaceTracker::calibrate() {
@ -634,12 +629,8 @@ void DdeFaceTracker::calibrate() {
_calibrationCount = 0;
_calibrationMessage = CALIBRATION_INSTRUCTION_MESSAGE + "\n\n";
// FIXME: this overlay probably doesn't work anymore
_calibrationBillboard = new TextOverlay();
_calibrationBillboard->setTopMargin(CALIBRATION_BILLBOARD_TOP_MARGIN);
_calibrationBillboard->setLeftMargin(CALIBRATION_BILLBOARD_LEFT_MARGIN);
_calibrationBillboard->setFontSize(CALIBRATION_BILLBOARD_FONT_SIZE);
_calibrationBillboard->setText(CALIBRATION_INSTRUCTION_MESSAGE);
_calibrationBillboard->setAlpha(CALIBRATION_BILLBOARD_ALPHA);
glm::vec2 viewport = qApp->getCanvasSize();
_calibrationBillboard->setX((viewport.x - CALIBRATION_BILLBOARD_WIDTH) / 2);
_calibrationBillboard->setY((viewport.y - CALIBRATION_BILLBOARD_HEIGHT) / 2);
@ -659,10 +650,10 @@ void DdeFaceTracker::addCalibrationDatum() {
int samplesLeft = CALIBRATION_SAMPLES - _calibrationCount;
if (samplesLeft % LARGE_TICK_INTERVAL == 0) {
_calibrationMessage += QString::number(samplesLeft / LARGE_TICK_INTERVAL);
_calibrationBillboard->setText(_calibrationMessage);
// FIXME: set overlay text
} else if (samplesLeft % SMALL_TICK_INTERVAL == 0) {
_calibrationMessage += ".";
_calibrationBillboard->setText(_calibrationMessage);
// FIXME: set overlay text
}
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {

View file

@ -32,6 +32,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class DdeFaceTracker : public FaceTracker, public Dependency {
@ -168,7 +169,7 @@ private:
int _calibrationCount;
QVector<float> _calibrationValues;
TextOverlay* _calibrationBillboard;
OverlayID _calibrationBillboardID;
QUuid _calibrationBillboardID;
QString _calibrationMessage;
bool _isCalibrated;
void addCalibrationDatum();

View file

@ -38,11 +38,13 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"OctreePacketProcessor::processPacket()");
#ifndef Q_OS_ANDROID
const int WAY_BEHIND = 300;
if (packetsToProcessCount() > WAY_BEHIND && qApp->getLogger()->extraDebugging()) {
qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
}
#endif
bool wasStatsPacket = false;

View file

@ -409,10 +409,6 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi
return std::make_shared<CollisionPickResult>(pick, entityIntersections, std::vector<ContactTestResult>());
}
PickResultPointer CollisionPick::getOverlayIntersection(const CollisionRegion& pick) {
return std::make_shared<CollisionPickResult>(pick, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
}
PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pick) {
if (!pick.loaded) {
// Cannot compute result

View file

@ -54,7 +54,6 @@ public:
return std::make_shared<CollisionPickResult>(pickVariant, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
}
PickResultPointer getEntityIntersection(const CollisionRegion& pick) override;
PickResultPointer getOverlayIntersection(const CollisionRegion& pick) override;
PickResultPointer getAvatarIntersection(const CollisionRegion& pick) override;
PickResultPointer getHUDIntersection(const CollisionRegion& pick) override;
Transform getResultTransform() const override;

View file

@ -17,6 +17,8 @@
#include "PickManager.h"
#include "RayPick.h"
#include "PolyLineEntityItem.h"
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover,
const PointerTriggers& triggers, bool faceAvatar, bool followNormal, float followNormalTime, bool centerEndY, bool lockEnd,
bool distanceScaleEnd, bool scaleWithParent, bool enabled) :
@ -28,7 +30,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
void LaserPointer::editRenderStatePath(const std::string& state, const QVariant& pathProps) {
auto renderState = std::static_pointer_cast<RenderState>(_renderStates[state]);
if (renderState) {
updateRenderStateOverlay(renderState->getPathID(), pathProps);
updateRenderState(renderState->getPathID(), pathProps);
QVariant lineWidth = pathProps.toMap()["lineWidth"];
if (lineWidth.isValid()) {
renderState->setLineWidth(lineWidth.toFloat());
@ -121,48 +123,62 @@ void LaserPointer::setVisualPickResultInternal(PickResultPointer pickResult, Int
}
}
LaserPointer::RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) :
LaserPointer::RenderState::RenderState(const QUuid& startID, const QUuid& pathID, const QUuid& endID) :
StartEndRenderState(startID, endID), _pathID(pathID)
{
if (!_pathID.isNull()) {
_pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignorePickIntersection").value.toBool();
_lineWidth = qApp->getOverlays().getProperty(_pathID, "lineWidth").value.toFloat();
if (!getPathID().isNull()) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
{
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
_pathIgnorePicks = entityScriptingInterface->getEntityProperties(getPathID(), desiredProperties).getIgnorePickIntersection();
}
{
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_STROKE_WIDTHS;
auto widths = entityScriptingInterface->getEntityProperties(getPathID(), desiredProperties).getStrokeWidths();
_lineWidth = widths.length() == 0 ? PolyLineEntityItem::DEFAULT_LINE_WIDTH : widths[0];
}
}
}
void LaserPointer::RenderState::cleanup() {
StartEndRenderState::cleanup();
if (!_pathID.isNull()) {
qApp->getOverlays().deleteOverlay(_pathID);
if (!getPathID().isNull()) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(getPathID());
}
}
void LaserPointer::RenderState::disable() {
StartEndRenderState::disable();
if (!getPathID().isNull()) {
QVariantMap pathProps;
pathProps.insert("visible", false);
pathProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getPathID(), pathProps);
EntityItemProperties properties;
properties.setVisible(false);
properties.setIgnorePickIntersection(true);
DependencyManager::get<EntityScriptingInterface>()->editEntity(getPathID(), properties);
}
}
void LaserPointer::RenderState::update(const glm::vec3& origin, const glm::vec3& end, const glm::vec3& surfaceNormal, float parentScale, bool distanceScaleEnd, bool centerEndY,
bool faceAvatar, bool followNormal, float followNormalStrength, float distance, const PickResultPointer& pickResult) {
StartEndRenderState::update(origin, end, surfaceNormal, parentScale, distanceScaleEnd, centerEndY, faceAvatar, followNormal, followNormalStrength, distance, pickResult);
QVariant endVariant = vec3toVariant(end);
if (!getPathID().isNull()) {
QVariantMap pathProps;
pathProps.insert("start", vec3toVariant(origin));
pathProps.insert("end", endVariant);
pathProps.insert("visible", true);
pathProps.insert("ignorePickIntersection", doesPathIgnoreRays());
pathProps.insert("lineWidth", getLineWidth() * parentScale);
qApp->getOverlays().editOverlay(getPathID(), pathProps);
EntityItemProperties properties;
QVector<glm::vec3> points;
points.append(glm::vec3(0.0f));
points.append(end - origin);
properties.setPosition(origin);
properties.setLinePoints(points);
properties.setVisible(true);
properties.setIgnorePickIntersection(doesPathIgnorePicks());
QVector<float> widths;
widths.append(getLineWidth() * parentScale);
DependencyManager::get<EntityScriptingInterface>()->editEntity(getPathID(), properties);
}
}
std::shared_ptr<StartEndRenderState> LaserPointer::buildRenderState(const QVariantMap& propMap) {
// FIXME: we have to keep using the Overlays interface here, because existing scripts use overlay properties to define pointers
QUuid startID;
if (propMap["start"].isValid()) {
QVariantMap startMap = propMap["start"].toMap();
@ -232,9 +248,8 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const P
glm::vec3 LaserPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::intersectRayWithEntityXYPlane(pickedObject.objectID, origin, direction);
case OVERLAY:
return RayPick::intersectRayWithOverlayXYPlane(pickedObject.objectID, origin, direction);
default:
return glm::vec3(NAN);
}

View file

@ -19,10 +19,10 @@ public:
class RenderState : public StartEndRenderState {
public:
RenderState() {}
RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID);
RenderState(const QUuid& startID, const QUuid& pathID, const QUuid& endID);
const OverlayID& getPathID() const { return _pathID; }
const bool& doesPathIgnoreRays() const { return _pathIgnoreRays; }
const QUuid& getPathID() const { return _pathID; }
const bool& doesPathIgnorePicks() const { return _pathIgnorePicks; }
void setLineWidth(float width) { _lineWidth = width; }
float getLineWidth() const { return _lineWidth; }
@ -33,9 +33,9 @@ public:
bool faceAvatar, bool followNormal, float followNormalStrength, float distance, const PickResultPointer& pickResult) override;
private:
OverlayID _pathID;
bool _pathIgnoreRays;
QUuid _pathID;
bool _pathIgnorePicks;
float _lineWidth;
};

View file

@ -27,6 +27,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
public:
@ -111,10 +112,10 @@ public:
* @function LaserPointers.setLockEndUUID
* @param {number} id
* @param {Uuid} itemID
* @param {boolean} isOverlay
* @param {boolean} isAvatar
* @param {Mat4} [offsetMat]
*/
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay, offsetMat); }
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); }
/**jsdoc

View file

@ -10,7 +10,6 @@
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "PickScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
@ -68,20 +67,15 @@ PickResultPointer ParabolaPick::getEntityIntersection(const PickParabola& pick)
DependencyManager::get<EntityScriptingInterface>()->evalParabolaIntersectionVector(pick, searchFilter,
getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (entityRes.intersects) {
return std::make_shared<ParabolaPickResult>(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.parabolicDistance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
}
}
return std::make_shared<ParabolaPickResult>(pick.toVariantMap());
}
PickResultPointer ParabolaPick::getOverlayIntersection(const PickParabola& pick) {
if (glm::length2(pick.acceleration) > EPSILON && glm::length2(pick.velocity) > EPSILON) {
bool precisionPicking = !(getFilter().isCoarse() || DependencyManager::get<PickManager>()->getForceCoarsePicking());
ParabolaToOverlayIntersectionResult overlayRes =
qApp->getOverlays().findParabolaIntersectionVector(pick, precisionPicking,
getIncludeItemsAs<OverlayID>(), getIgnoreItemsAs<OverlayID>(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
if (overlayRes.intersects) {
return std::make_shared<ParabolaPickResult>(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.parabolicDistance, overlayRes.intersection, pick, overlayRes.surfaceNormal, overlayRes.extraInfo);
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityRes.entityID, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
return std::make_shared<ParabolaPickResult>(type, entityRes.entityID, entityRes.distance, entityRes.parabolicDistance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
}
}
return std::make_shared<ParabolaPickResult>(pick.toVariantMap());

View file

@ -12,7 +12,6 @@
#include <Pick.h>
class EntityItemID;
class OverlayID;
class ParabolaPickResult : public PickResult {
public:
@ -80,7 +79,6 @@ public:
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { return std::make_shared<ParabolaPickResult>(pickVariant); }
PickResultPointer getEntityIntersection(const PickParabola& pick) override;
PickResultPointer getOverlayIntersection(const PickParabola& pick) override;
PickResultPointer getAvatarIntersection(const PickParabola& pick) override;
PickResultPointer getHUDIntersection(const PickParabola& pick) override;
Transform getResultTransform() const override;

View file

@ -149,7 +149,7 @@ void ParabolaPointer::setVisualPickResultInternal(PickResultPointer pickResult,
}
}
ParabolaPointer::RenderState::RenderState(const OverlayID& startID, const OverlayID& endID, const glm::vec3& pathColor, float pathAlpha, float pathWidth,
ParabolaPointer::RenderState::RenderState(const QUuid& startID, const QUuid& endID, const glm::vec3& pathColor, float pathAlpha, float pathWidth,
bool isVisibleInSecondaryCamera, bool drawInFront, bool pathEnabled) :
StartEndRenderState(startID, endID)
{
@ -230,6 +230,7 @@ void ParabolaPointer::RenderState::update(const glm::vec3& origin, const glm::ve
}
std::shared_ptr<StartEndRenderState> ParabolaPointer::buildRenderState(const QVariantMap& propMap) {
// FIXME: we have to keep using the Overlays interface here, because existing scripts use overlay properties to define pointers
QUuid startID;
if (propMap["start"].isValid()) {
QVariantMap startMap = propMap["start"].toMap();
@ -321,9 +322,8 @@ glm::vec3 ParabolaPointer::findIntersection(const PickedObject& pickedObject, co
// TODO: implement
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
//return ParabolaPick::intersectParabolaWithEntityXYPlane(pickedObject.objectID, origin, velocity, acceleration);
case OVERLAY:
//return ParabolaPick::intersectParabolaWithOverlayXYPlane(pickedObject.objectID, origin, velocity, acceleration);
default:
return glm::vec3(NAN);
}

View file

@ -10,6 +10,8 @@
#include "PathPointer.h"
#include <render/Item.h>
class ParabolaPointer : public PathPointer {
using Parent = PathPointer;
public:
@ -79,7 +81,7 @@ public:
};
RenderState() {}
RenderState(const OverlayID& startID, const OverlayID& endID, const glm::vec3& pathColor, float pathAlpha, float parentScale,
RenderState(const QUuid& startID, const QUuid& endID, const glm::vec3& pathColor, float pathAlpha, float parentScale,
bool isVisibleInSecondaryCamera, bool drawInFront, bool pathEnabled);
void setPathWidth(float width) { _pathWidth = width; }

View file

@ -73,10 +73,10 @@ void PathPointer::setLength(float length) {
});
}
void PathPointer::setLockEndUUID(const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat) {
void PathPointer::setLockEndUUID(const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat) {
withWriteLock([&] {
_lockEndObject.id = objectID;
_lockEndObject.isOverlay = isOverlay;
_lockEndObject.isAvatar = isAvatar;
_lockEndObject.offsetMat = offsetMat;
});
}
@ -97,12 +97,8 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick
glm::quat rot;
glm::vec3 dim;
glm::vec3 registrationPoint;
if (_lockEndObject.isOverlay) {
pos = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "position").value);
rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value);
dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value);
registrationPoint = glm::vec3(0.5f);
} else {
// TODO: use isAvatar
{
EntityItemProperties props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(_lockEndObject.id);
glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition());
glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat;
@ -117,7 +113,7 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick
distance = glm::distance(origin, endVec);
glm::vec3 normalizedDirection = glm::normalize(direction);
type = _lockEndObject.isOverlay ? IntersectionType::OVERLAY : IntersectionType::ENTITY;
type = IntersectionType::ENTITY;
id = _lockEndObject.id;
intersection = endVec;
surfaceNormal = -normalizedDirection;
@ -126,8 +122,6 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick
id = getPickedObjectID(pickResult);
if (type == IntersectionType::ENTITY) {
endVec = DependencyManager::get<EntityScriptingInterface>()->getEntityTransform(id)[3];
} else if (type == IntersectionType::OVERLAY) {
endVec = vec3FromVariant(qApp->getOverlays().getProperty(id, "position").value);
} else if (type == IntersectionType::AVATAR) {
endVec = DependencyManager::get<AvatarHashMap>()->getAvatar(id)->getPosition();
}
@ -184,8 +178,8 @@ void PathPointer::editRenderState(const std::string& state, const QVariant& star
withWriteLock([&] {
auto renderState = _renderStates.find(state);
if (renderState != _renderStates.end()) {
updateRenderStateOverlay(renderState->second->getStartID(), startProps);
updateRenderStateOverlay(renderState->second->getEndID(), endProps);
updateRenderState(renderState->second->getStartID(), startProps);
updateRenderState(renderState->second->getEndID(), endProps);
QVariant startDim = startProps.toMap()["dimensions"];
if (startDim.isValid()) {
renderState->second->setStartDim(vec3FromVariant(startDim));
@ -204,7 +198,8 @@ void PathPointer::editRenderState(const std::string& state, const QVariant& star
});
}
void PathPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& props) {
void PathPointer::updateRenderState(const QUuid& id, const QVariant& props) {
// FIXME: we have to keep using the Overlays interface here, because existing scripts use overlay properties to define pointers
if (!id.isNull() && props.isValid()) {
QVariantMap propMap = props.toMap();
propMap.remove("visible");
@ -249,65 +244,79 @@ Pointer::Buttons PathPointer::getPressedButtons(const PickResultPointer& pickRes
return toReturn;
}
StartEndRenderState::StartEndRenderState(const OverlayID& startID, const OverlayID& endID) :
StartEndRenderState::StartEndRenderState(const QUuid& startID, const QUuid& endID) :
_startID(startID), _endID(endID) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!_startID.isNull()) {
_startDim = vec3FromVariant(qApp->getOverlays().getProperty(_startID, "dimensions").value);
_startIgnoreRays = qApp->getOverlays().getProperty(_startID, "ignorePickIntersection").value.toBool();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
auto properties = entityScriptingInterface->getEntityProperties(_startID, desiredProperties);
_startDim = properties.getDimensions();
_startIgnorePicks = properties.getIgnorePickIntersection();
}
if (!_endID.isNull()) {
_endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value);
_endRot = quatFromVariant(qApp->getOverlays().getProperty(_endID, "rotation").value);
_endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignorePickIntersection").value.toBool();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_ROTATION;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
auto properties = entityScriptingInterface->getEntityProperties(_endID, desiredProperties);
_endDim = properties.getDimensions();
_endRot = properties.getRotation();
_endIgnorePicks = properties.getIgnorePickIntersection();
}
}
void StartEndRenderState::cleanup() {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!_startID.isNull()) {
qApp->getOverlays().deleteOverlay(_startID);
entityScriptingInterface->deleteEntity(_startID);
}
if (!_endID.isNull()) {
qApp->getOverlays().deleteOverlay(_endID);
entityScriptingInterface->deleteEntity(_endID);
}
}
void StartEndRenderState::disable() {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!getStartID().isNull()) {
QVariantMap startProps;
startProps.insert("visible", false);
startProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getStartID(), startProps);
EntityItemProperties properties;
properties.setVisible(false);
properties.setIgnorePickIntersection(true);
entityScriptingInterface->editEntity(getStartID(), properties);
}
if (!getEndID().isNull()) {
QVariantMap endProps;
endProps.insert("visible", false);
endProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getEndID(), endProps);
EntityItemProperties properties;
properties.setVisible(false);
properties.setIgnorePickIntersection(true);
entityScriptingInterface->editEntity(getEndID(), properties);
}
_enabled = false;
}
void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end, const glm::vec3& surfaceNormal, float parentScale, bool distanceScaleEnd, bool centerEndY,
bool faceAvatar, bool followNormal, float followNormalStrength, float distance, const PickResultPointer& pickResult) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!getStartID().isNull()) {
QVariantMap startProps;
startProps.insert("position", vec3toVariant(origin));
startProps.insert("visible", true);
startProps.insert("dimensions", vec3toVariant(getStartDim() * parentScale));
startProps.insert("ignorePickIntersection", doesStartIgnoreRays());
qApp->getOverlays().editOverlay(getStartID(), startProps);
EntityItemProperties properties;
properties.setPosition(origin);
properties.setVisible(true);
properties.setDimensions(getStartDim() * parentScale);
properties.setIgnorePickIntersection(doesStartIgnorePicks());
entityScriptingInterface->editEntity(getStartID(), properties);
}
if (!getEndID().isNull()) {
QVariantMap endProps;
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(getEndID(), "dimensions").value);
EntityItemProperties properties;
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
glm::vec3 dim;
if (distanceScaleEnd) {
dim = getEndDim() * glm::distance(origin, end);
endProps.insert("dimensions", vec3toVariant(dim));
} else {
dim = getEndDim() * parentScale;
endProps.insert("dimensions", vec3toVariant(dim));
}
properties.setDimensions(dim);
glm::quat normalQuat = Quat().lookAtSimple(Vectors::ZERO, surfaceNormal);
normalQuat = normalQuat * glm::quat(glm::vec3(-M_PI_2, 0, 0));
@ -343,11 +352,11 @@ void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end,
_avgEndRot = rotation;
}
}
endProps.insert("position", vec3toVariant(position));
endProps.insert("rotation", quatToVariant(rotation));
endProps.insert("visible", true);
endProps.insert("ignorePickIntersection", doesEndIgnoreRays());
qApp->getOverlays().editOverlay(getEndID(), endProps);
properties.setPosition(position);
properties.setRotation(rotation);
properties.setVisible(true);
properties.setIgnorePickIntersection(doesEndIgnorePicks());
entityScriptingInterface->editEntity(getEndID(), properties);
}
_enabled = true;
}
@ -355,9 +364,8 @@ void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end,
glm::vec2 PathPointer::findPos2D(const PickedObject& pickedObject, const glm::vec3& origin) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::projectOntoEntityXYPlane(pickedObject.objectID, origin);
case OVERLAY:
return RayPick::projectOntoOverlayXYPlane(pickedObject.objectID, origin);
case HUD:
return DependencyManager::get<PickManager>()->calculatePos2DFromHUD(origin);
default:

View file

@ -12,27 +12,25 @@
#include <QString>
#include <glm/glm.hpp>
#include "ui/overlays/Overlay.h"
#include <Pointer.h>
#include <Pick.h>
struct LockEndObject {
QUuid id { QUuid() };
bool isOverlay { false };
bool isAvatar { false };
glm::mat4 offsetMat { glm::mat4() };
};
class StartEndRenderState {
public:
StartEndRenderState() {}
StartEndRenderState(const OverlayID& startID, const OverlayID& endID);
StartEndRenderState(const QUuid& startID, const QUuid& endID);
virtual ~StartEndRenderState() = default;
const OverlayID& getStartID() const { return _startID; }
const OverlayID& getEndID() const { return _endID; }
const bool& doesStartIgnoreRays() const { return _startIgnoreRays; }
const bool& doesEndIgnoreRays() const { return _endIgnoreRays; }
const QUuid& getStartID() const { return _startID; }
const QUuid& getEndID() const { return _endID; }
const bool& doesStartIgnorePicks() const { return _startIgnorePicks; }
const bool& doesEndIgnorePicks() const { return _endIgnorePicks; }
void setStartDim(const glm::vec3& startDim) { _startDim = startDim; }
const glm::vec3& getStartDim() const { return _startDim; }
@ -51,10 +49,10 @@ public:
bool isEnabled() const { return _enabled; }
protected:
OverlayID _startID;
OverlayID _endID;
bool _startIgnoreRays;
bool _endIgnoreRays;
QUuid _startID;
QUuid _endID;
bool _startIgnorePicks;
bool _endIgnorePicks;
glm::vec3 _startDim;
glm::vec3 _endDim;
@ -78,11 +76,11 @@ public:
virtual ~PathPointer();
void setRenderState(const std::string& state) override;
// You cannot use editRenderState to change the type of any part of the pointer. You can only edit the properties of the existing overlays.
// You cannot use editRenderState to change the type of any part of the pointer. You can only edit the properties of the existing parts.
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override;
void setLength(float length) override;
void setLockEndUUID(const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) override;
void setLockEndUUID(const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) override;
void updateVisuals(const PickResultPointer& prevRayPickResult) override;
@ -119,7 +117,7 @@ protected:
bool shouldHover(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
bool shouldTrigger(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
void updateRenderState(const QUuid& id, const QVariant& props);
virtual void editRenderStatePath(const std::string& state, const QVariant& pathProps) = 0;
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;

View file

@ -26,7 +26,6 @@
#include "avatar/AvatarManager.h"
#include "NestableTransformNode.h"
#include "avatars-renderer/AvatarTransformNode.h"
#include "ui/overlays/OverlayTransformNode.h"
#include "EntityTransformNode.h"
#include <ScriptEngine.h>
@ -61,7 +60,7 @@ PickFilter getPickFilter(unsigned int filter) {
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
* @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
* @property {Vec3} [posOffset=Vec3.ZERO] Only for Joint Ray Picks. A local joint position offset, in meters. x = upward, y = forward, z = lateral
@ -161,7 +160,7 @@ unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
* @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
* @property {Vec3} [posOffset=Vec3.ZERO] Only for Joint Parabola Picks. A local joint position offset, in meters. x = upward, y = forward, z = lateral
@ -264,7 +263,7 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti
* The depth is measured in world space, but will scale with the parent if defined.
* @property {CollisionMask} [collisionGroup=8] - The type of object this collision pick collides as. Objects whose collision masks overlap with the pick's collision group
* will be considered colliding with the pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
* @property {boolean} [scaleWithParent=true] If true, the collision pick's dimensions and threshold will adjust according to the scale of the parent.
@ -415,8 +414,6 @@ void PickScriptingInterface::setParentTransform(std::shared_ptr<PickQuery> pick,
NestableType nestableType = sharedNestablePointer->getNestableType();
if (nestableType == NestableType::Avatar) {
pick->parentTransform = std::make_shared<AvatarTransformNode>(std::static_pointer_cast<Avatar>(sharedNestablePointer), parentJointIndex);
} else if (nestableType == NestableType::Overlay) {
pick->parentTransform = std::make_shared<OverlayTransformNode>(std::static_pointer_cast<Base3DOverlay>(sharedNestablePointer), parentJointIndex);
} else if (nestableType == NestableType::Entity) {
pick->parentTransform = std::make_shared<EntityTransformNode>(std::static_pointer_cast<EntityItem>(sharedNestablePointer), parentJointIndex);
} else {

View file

@ -23,6 +23,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} PICK_ENTITIES A filter flag. Include domain and avatar entities when intersecting. <em>Read-only.</em>. Deprecated.
* @property {number} PICK_OVERLAYS A filter flag. Include local entities when intersecting. <em>Read-only.</em>. Deprecated.
@ -46,7 +47,8 @@
*
* @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags. <em>Read-only.</em>
* @property {number} INTERSECTED_ENTITY An intersection type. Intersected an entity. <em>Read-only.</em>
* @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an overlay. <em>Read-only.</em>
* @property {number} INTERSECTED_LOCAL_ENTITY An intersection type. Intersected a local entity.</em>
* @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an entity (3D Overlays no longer exist). <em>Read-only.</em>
* @property {number} INTERSECTED_AVATAR An intersection type. Intersected an avatar. <em>Read-only.</em>
* @property {number} INTERSECTED_HUD An intersection type. Intersected the HUD sphere. <em>Read-only.</em>
* @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results.
@ -76,6 +78,7 @@ class PickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_LOCAL_ENTITY READ INTERSECTED_LOCAL_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
@ -211,7 +214,7 @@ public:
Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking);
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to ignore during intersection. Not used by Stylus Picks.
* Sets a list of Entity IDs and/or Avatar IDs to ignore during intersection. Not used by Stylus Picks.
* @function Picks.setIgnoreItems
* @param {number} uid The ID of the Pick, as returned by {@link Picks.createPick}.
* @param {Uuid[]} ignoreItems A list of IDs to ignore.
@ -219,7 +222,7 @@ public:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems);
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Sets a list of Entity IDs and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Picks <b>only</b> intersect with objects in their include list.
* @function Picks.setIncludeItems
* @param {number} uid The ID of the Pick, as returned by {@link Picks.createPick}.
@ -348,7 +351,13 @@ public slots:
* @function Picks.INTERSECTED_OVERLAY
* @returns {number}
*/
static constexpr unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; }
static constexpr unsigned int INTERSECTED_LOCAL_ENTITY() { return IntersectionType::LOCAL_ENTITY; }
/**jsdoc
* @function Picks.INTERSECTED_OVERLAY
* @returns {number}
*/
static constexpr unsigned int INTERSECTED_OVERLAY() { return INTERSECTED_LOCAL_ENTITY(); }
/**jsdoc
* @function Picks.INTERSECTED_AVATAR

View file

@ -99,7 +99,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
}
}
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<StylusPointer>(properties, StylusPointer::buildStylusOverlay(propertyMap), hover, enabled, modelPositionOffset,
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<StylusPointer>(properties, StylusPointer::buildStylus(propertyMap), hover, enabled, modelPositionOffset,
modelRotationOffset, modelDimensions));
}
@ -116,15 +116,15 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
*
* @typedef {object} Pointers.RayPointerRenderState
* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Ray Pointer,
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined object to represent the beginning of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [path] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the path of the Ray Pointer,
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [path] When using {@link Pointers.createPointer}, an optionally defined object to represent the path of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field), which <b>must</b> be <code>"line3d"</code>.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the end of the Ray Pointer,
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined object to represent the end of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
@ -271,14 +271,14 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
*
* @typedef {object} Pointers.ParabolaPointerRenderState
* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Parabola Pointer,
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined object to represent the beginning of the Parabola Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Pointers.ParabolaProperties} [path] When using {@link Pointers.createPointer}, the optionally defined rendering properties of the parabolic path defined by the Parabola Pointer.
* Not defined in {@link Pointers.getPointerProperties}.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the end of the Parabola Pointer,
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined object to represent the end of the Parabola Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.

View file

@ -16,12 +16,13 @@
/**jsdoc
* The Pointers API lets you create and manage objects for repeatedly calculating intersections in different ways, as well as the visual representation of those objects.
* Pointers can also be configured to automatically generate {@link PointerEvent}s on {@link Entities} and {@link Overlays}.
* Pointers can also be configured to automatically generate {@link PointerEvent}s on {@link Entities}.
*
* @namespace Pointers
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class PointerScriptingInterface : public QObject, public Dependency {
@ -39,7 +40,7 @@ public:
* @typedef {object} Pointers.Trigger
* @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger <code>button</code>.
* @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered,
* it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
* it will try to set the entity focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
*/
/**jsdoc
@ -153,7 +154,7 @@ public:
Q_INVOKABLE void setLength(unsigned int uid, float length) const { DependencyManager::get<PointerManager>()->setLength(uid, length); }
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to ignore during intersection. Not used by Stylus Pointers.
* Sets a list of Entity IDs and/or Avatar IDs to ignore during intersection. Not used by Stylus Pointers.
* @function Pointers.setIgnoreItems
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid[]} ignoreItems A list of IDs to ignore.
@ -161,7 +162,7 @@ public:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const;
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Sets a list of Entity IDs and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Pointers <b>only</b> intersect with objects in their include list.
* @function Pointers.setIncludeItems
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
@ -171,15 +172,15 @@ public:
/**jsdoc
* Lock a Pointer onto a specific object (overlay, entity, or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object.
* Lock a Pointer onto a specific object (entity or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object.
* Not used by Stylus Pointers.
* @function Pointers.setLockEndUUID
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid} objectID The ID of the object to which to lock on.
* @param {boolean} isOverlay False for entities or avatars, true for overlays
* @param {boolean} isAvatar False for entities, true for avatars
* @param {Mat4} [offsetMat] The offset matrix to use if you do not want to lock on to the center of the object.
*/
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay, offsetMat); }
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); }
/**jsdoc
@ -211,7 +212,7 @@ public:
* @function Pointers.getPointerProperties
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {Pointers.LaserPointerProperties|Pointers.StylusPointerProperties|Pointers.ParabolaPointerProperties} The information about the Pointer.
* Currently only includes renderStates and defaultRenderStates with associated overlay IDs.
* Currently only includes renderStates and defaultRenderStates with associated entity IDs.
*/
Q_INVOKABLE QVariantMap getPointerProperties(unsigned int uid) const;
};

View file

@ -9,7 +9,6 @@
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
@ -37,19 +36,15 @@ PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) {
DependencyManager::get<EntityScriptingInterface>()->evalRayIntersectionVector(pick, searchFilter,
getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (entityRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
}
PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
bool precisionPicking = !(getFilter().isCoarse() || DependencyManager::get<PickManager>()->getForceCoarsePicking());
RayToOverlayIntersectionResult overlayRes =
qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking,
getIncludeItemsAs<OverlayID>(), getIgnoreItemsAs<OverlayID>(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
if (overlayRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, pick, overlayRes.surfaceNormal, overlayRes.extraInfo);
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityRes.entityID, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
return std::make_shared<RayPickResult>(type, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
@ -89,12 +84,6 @@ glm::vec3 RayPick::intersectRayWithXYPlane(const glm::vec3& origin, const glm::v
return origin + t * direction;
}
glm::vec3 RayPick::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) {
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
return intersectRayWithXYPlane(origin, direction, position, rotation, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT);
}
glm::vec3 RayPick::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint());
@ -113,15 +102,12 @@ glm::vec2 RayPick::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3
return pos2D;
}
glm::vec2 RayPick::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized) {
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
glm::vec3 dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f);
return projectOntoXYPlane(worldPos, position, rotation, dimensions, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT, unNormalized);
}
glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_REGISTRATION_POINT;
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID, desiredProperties);
return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized);
}

View file

@ -12,7 +12,6 @@
#include <Pick.h>
class EntityItemID;
class OverlayID;
class RayPickResult : public PickResult {
public:
@ -78,16 +77,13 @@ public:
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { return std::make_shared<RayPickResult>(pickVariant); }
PickResultPointer getEntityIntersection(const PickRay& pick) override;
PickResultPointer getOverlayIntersection(const PickRay& pick) override;
PickResultPointer getAvatarIntersection(const PickRay& pick) override;
PickResultPointer getHUDIntersection(const PickRay& pick) override;
Transform getResultTransform() const override;
// These are helper functions for projecting and intersecting rays
static glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction);
static glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction);
static glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized = true);
static glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized = true);
private:
static glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration);

View file

@ -25,6 +25,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} PICK_ENTITIES <em>Read-only.</em>
* @property {number} PICK_OVERLAYS <em>Read-only.</em>
@ -53,6 +54,7 @@ class RayPickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_LOCAL_ENTITY READ INTERSECTED_LOCAL_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
@ -202,7 +204,13 @@ public slots:
* @function RayPick.INTERSECTED_OVERLAY
* @returns {number}
*/
static unsigned int INTERSECTED_OVERLAY() { return PickScriptingInterface::INTERSECTED_OVERLAY(); }
static unsigned int INTERSECTED_LOCAL_ENTITY() { return PickScriptingInterface::INTERSECTED_LOCAL_ENTITY(); }
/**jsdoc
* @function RayPick.INTERSECTED_OVERLAY
* @returns {number}
*/
static unsigned int INTERSECTED_OVERLAY() { return PickScriptingInterface::INTERSECTED_LOCAL_ENTITY(); }
/**jsdoc
* @function RayPick.INTERSECTED_AVATAR

View file

@ -11,8 +11,6 @@
#include <glm/glm.hpp>
#include "ui/overlays/Base3DOverlay.h"
#include "Application.h"
#include <DependencyManager.h>
#include "avatar/AvatarManager.h"
@ -20,6 +18,8 @@
#include <controllers/StandardControls.h>
#include <controllers/UserInputMapper.h>
#include <EntityTreeElement.h>
using namespace bilateral;
float StylusPick::WEB_STYLUS_LENGTH = 0.2f;
@ -148,7 +148,7 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
continue;
}
if (!entity->getVisible() && !getFilter().doesPickInvisible()) {
if (!EntityTreeElement::checkFilterSettings(entity, getFilter())) {
continue;
}
@ -161,47 +161,15 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false);
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
results.push_back(StylusPickResult(IntersectionType::ENTITY, target, distance, intersection, pick, normal));
}
}
StylusPickResult nearestTarget(pick.toVariantMap());
for (const auto& result : results) {
if (result.distance < nearestTarget.distance) {
nearestTarget = result;
}
}
return std::make_shared<StylusPickResult>(nearestTarget);
}
PickResultPointer StylusPick::getOverlayIntersection(const StylusTip& pick) {
std::vector<StylusPickResult> results;
for (const auto& target : getIncludeItems()) {
if (target.isNull()) {
continue;
}
auto overlay = qApp->getOverlays().getOverlay(target);
// Don't interact with non-3D or invalid overlays
if (!overlay || !overlay->is3D()) {
continue;
}
if (!overlay->getVisible() && !getFilter().doesPickInvisible()) {
continue;
}
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
const auto overlayRotation = overlay3D->getWorldOrientation();
const auto overlayPosition = overlay3D->getWorldPosition();
glm::vec3 normal = overlayRotation * Vectors::UNIT_Z;
float distance = glm::dot(pick.position - overlayPosition, normal);
glm::vec3 intersection = pick.position - (normal * distance);
glm::vec2 pos2D = RayPick::projectOntoOverlayXYPlane(target, intersection, false);
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
results.push_back(StylusPickResult(IntersectionType::OVERLAY, target, distance, intersection, pick, normal));
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(target, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
results.push_back(StylusPickResult(type, target, distance, intersection, pick, normal));
}
}

View file

@ -63,7 +63,6 @@ public:
StylusTip getMathematicalPick() const override;
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override;
PickResultPointer getEntityIntersection(const StylusTip& pick) override;
PickResultPointer getOverlayIntersection(const StylusTip& pick) override;
PickResultPointer getAvatarIntersection(const StylusTip& pick) override;
PickResultPointer getHUDIntersection(const StylusTip& pick) override;
Transform getResultTransform() const override;

View file

@ -27,10 +27,10 @@ static const float TOUCH_HYSTERESIS = 0.001f;
static const QString DEFAULT_STYLUS_MODEL_URL = PathUtils::resourcesUrl() + "/meshes/tablet-stylus-fat.fbx";
StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled,
StylusPointer::StylusPointer(const QVariant& props, const QUuid& stylus, bool hover, bool enabled,
const glm::vec3& modelPositionOffset, const glm::quat& modelRotationOffset, const glm::vec3& modelDimensions) :
Pointer(DependencyManager::get<PickScriptingInterface>()->createStylusPick(props), enabled, hover),
_stylusOverlay(stylusOverlay),
_stylus(stylus),
_modelPositionOffset(modelPositionOffset),
_modelDimensions(modelDimensions),
_modelRotationOffset(modelRotationOffset)
@ -38,13 +38,14 @@ StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverl
}
StylusPointer::~StylusPointer() {
if (!_stylusOverlay.isNull()) {
qApp->getOverlays().deleteOverlay(_stylusOverlay);
if (!_stylus.isNull()) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_stylus);
}
}
OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) {
QVariantMap overlayProperties;
QUuid StylusPointer::buildStylus(const QVariantMap& properties) {
// FIXME: we have to keep using the Overlays interface here, because existing scripts use overlay properties to define pointers
QVariantMap propertiesMap;
QString modelUrl = DEFAULT_STYLUS_MODEL_URL;
@ -56,15 +57,15 @@ OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) {
}
}
// TODO: make these configurable per pointer
overlayProperties["name"] = "stylus";
overlayProperties["url"] = modelUrl;
overlayProperties["loadPriority"] = 10.0f;
overlayProperties["solid"] = true;
overlayProperties["visible"] = false;
overlayProperties["ignorePickIntersection"] = true;
overlayProperties["drawInFront"] = false;
propertiesMap["name"] = "stylus";
propertiesMap["url"] = modelUrl;
propertiesMap["loadPriority"] = 10.0f;
propertiesMap["solid"] = true;
propertiesMap["visible"] = false;
propertiesMap["ignorePickIntersection"] = true;
propertiesMap["drawInFront"] = false;
return qApp->getOverlays().addOverlay("model", overlayProperties);
return qApp->getOverlays().addOverlay("model", propertiesMap);
}
void StylusPointer::updateVisuals(const PickResultPointer& pickResult) {
@ -83,25 +84,25 @@ void StylusPointer::updateVisuals(const PickResultPointer& pickResult) {
}
void StylusPointer::show(const StylusTip& tip) {
if (!_stylusOverlay.isNull()) {
QVariantMap props;
if (!_stylus.isNull()) {
auto modelOrientation = tip.orientation * _modelRotationOffset;
auto sensorToWorldScale = DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
auto modelPositionOffset = modelOrientation * (_modelPositionOffset * sensorToWorldScale);
props["position"] = vec3toVariant(tip.position + modelPositionOffset);
props["rotation"] = quatToVariant(modelOrientation);
props["dimensions"] = vec3toVariant(sensorToWorldScale * _modelDimensions);
props["visible"] = true;
qApp->getOverlays().editOverlay(_stylusOverlay, props);
EntityItemProperties properties;
properties.setPosition(tip.position + modelPositionOffset);
properties.setRotation(modelOrientation);
properties.setDimensions(sensorToWorldScale * _modelDimensions);
properties.setVisible(true);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_stylus, properties);
}
_showing = true;
}
void StylusPointer::hide() {
if (!_stylusOverlay.isNull()) {
QVariantMap props;
props.insert("visible", false);
qApp->getOverlays().editOverlay(_stylusOverlay, props);
if (!_stylus.isNull()) {
EntityItemProperties properties;
properties.setVisible(false);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_stylus, properties);
}
_showing = false;
}
@ -234,9 +235,8 @@ QVariantMap StylusPointer::toVariantMap() const {
glm::vec3 StylusPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::intersectRayWithEntityXYPlane(pickedObject.objectID, origin, direction);
case OVERLAY:
return RayPick::intersectRayWithOverlayXYPlane(pickedObject.objectID, origin, direction);
default:
return glm::vec3(NAN);
}
@ -245,9 +245,8 @@ glm::vec3 StylusPointer::findIntersection(const PickedObject& pickedObject, cons
glm::vec2 StylusPointer::findPos2D(const PickedObject& pickedObject, const glm::vec3& origin) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::projectOntoEntityXYPlane(pickedObject.objectID, origin);
case OVERLAY:
return RayPick::projectOntoOverlayXYPlane(pickedObject.objectID, origin);
case HUD:
return DependencyManager::get<PickManager>()->calculatePos2DFromHUD(origin);
default:

View file

@ -12,8 +12,6 @@
#include <shared/Bilateral.h>
#include <RegisteredMetaTypes.h>
#include "ui/overlays/Overlay.h"
#include "StylusPick.h"
class StylusPointer : public Pointer {
@ -21,7 +19,7 @@ class StylusPointer : public Pointer {
using Ptr = std::shared_ptr<StylusPointer>;
public:
StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled,
StylusPointer(const QVariant& props, const QUuid& stylus, bool hover, bool enabled,
const glm::vec3& modelPositionOffset, const glm::quat& modelRotationOffset, const glm::vec3& modelDimensions);
~StylusPointer();
@ -36,7 +34,7 @@ public:
QVariantMap toVariantMap() const override;
static OverlayID buildStylusOverlay(const QVariantMap& properties);
static QUuid buildStylus(const QVariantMap& properties);
protected:
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;
@ -74,7 +72,7 @@ private:
RenderState _renderState { EVENTS_ON };
const OverlayID _stylusOverlay;
QUuid _stylus;
static bool isWithinBounds(float distance, float min, float max, float hysteresis);
static glm::vec3 findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction);

View file

@ -42,6 +42,7 @@ class AccountServicesScriptingInterface : public QObject {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @namespace AccountServices
* @property {string} username <em>Read-only.</em>

View file

@ -32,6 +32,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
* @hifi-server-entity
* @hifi-assignment-client
*

View file

@ -24,6 +24,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class ClipboardScriptingInterface : public QObject {
Q_OBJECT

View file

@ -199,6 +199,7 @@ class ScriptEngine;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end
* points in a {@link RouteObject} mapping. A synonym for <code>Controller.Hardware.Actions</code>.

View file

@ -24,7 +24,8 @@
*
* @hifi-interface
* @hifi-client-entity
*
* @hifi-avatar
*
* @property {number} width
* @property {number} height
* @property {number} ALWAYS_ON_TOP - InteractiveWindow flag for always showing a window on top

View file

@ -21,6 +21,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class GooglePolyScriptingInterface : public QObject, public Dependency {

View file

@ -31,6 +31,7 @@ class QScriptEngine;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Vec3} position - The position of the HMD if currently in VR display mode, otherwise
* {@link Vec3(0)|Vec3.ZERO}. <em>Read-only.</em>
@ -53,12 +54,12 @@ class QScriptEngine;
* @property {boolean} tabletContextualMode - <code>true</code> if the tablet has been opened in contextual mode, otherwise
* <code>false</code>. In contextual mode, the tablet has been opened at a specific world position and orientation rather
* than at a position and orientation relative to the user. <em>Read-only.</em>
* @property {Uuid} tabletID - The UUID of the tablet body model overlay.
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen overlay.
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button overlay.
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight overlay.
* @property {Uuid} miniTabletID - The UUID of the mini tablet's body model overlay. <code>null</code> if not in HMD mode.
* @property {Uuid} miniTabletScreenID - The UUID of the mini tablet's screen overlay. <code>null</code> if not in HMD mode.
* @property {Uuid} tabletID - The UUID of the tablet body model entity.
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen entity.
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button entity.
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight entity.
* @property {Uuid} miniTabletID - The UUID of the mini tablet's body model entity. <code>null</code> if not in HMD mode.
* @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

View file

@ -64,6 +64,6 @@ bool KeyboardScriptingInterface::getPreferMalletsOverLasers() const {
return DependencyManager::get<Keyboard>()->getPreferMalletsOverLasers();
}
bool KeyboardScriptingInterface::containsID(OverlayID overlayID) const {
return DependencyManager::get<Keyboard>()->containsID(overlayID);
bool KeyboardScriptingInterface::containsID(const QUuid& id) const {
return DependencyManager::get<Keyboard>()->containsID(id);
}

View file

@ -16,7 +16,6 @@
#include <QtCore/QUuid>
#include "DependencyManager.h"
#include "ui/overlays/Overlay.h"
/**jsdoc
* The Keyboard API provides facilities to use 3D Physical keyboard.
@ -24,6 +23,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {bool} raised - <code>true</code> If the keyboard is visible <code>false</code> otherwise
* @property {bool} password - <code>true</code> Will show * instead of characters in the text display <code>false</code> otherwise
@ -46,7 +46,7 @@ public:
Q_INVOKABLE void disableRightMallet();
Q_INVOKABLE void setLeftHandLaser(unsigned int leftHandLaser);
Q_INVOKABLE void setRightHandLaser(unsigned int rightHandLaser);
Q_INVOKABLE bool containsID(OverlayID overlayID) const;
Q_INVOKABLE bool containsID(const QUuid& overlayID) const;
private:
bool getPreferMalletsOverLasers() const;
bool isRaised() const;

View file

@ -35,6 +35,7 @@ class MenuItemProperties;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
/**

View file

@ -40,19 +40,6 @@ bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) {
return true;
}
bool GameplayObjects::addToGameplayObjects(const OverlayID& overlayID) {
containsData = true;
if (std::find(_overlayIDs.begin(), _overlayIDs.end(), overlayID) == _overlayIDs.end()) {
_overlayIDs.push_back(overlayID);
}
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const OverlayID& overlayID) {
_overlayIDs.erase(std::remove(_overlayIDs.begin(), _overlayIDs.end(), overlayID), _overlayIDs.end());
return true;
}
SelectionScriptingInterface::SelectionScriptingInterface() {
}
@ -64,7 +51,6 @@ SelectionScriptingInterface::SelectionScriptingInterface() {
* <tbody>
* <tr><td><code>"avatar"</code></td><td></td></tr>
* <tr><td><code>"entity"</code></td><td></td></tr>
* <tr><td><code>"overlay"</code></td><td></td></tr>
* </tbody>
* </table>
* @typedef {string} Selection.ItemType
@ -72,20 +58,16 @@ SelectionScriptingInterface::SelectionScriptingInterface() {
bool SelectionScriptingInterface::addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) {
if (itemType == "avatar") {
return addToGameplayObjects(listName, (QUuid)id);
} else if (itemType == "entity") {
} else if (itemType == "entity" || itemType == "overlay") {
return addToGameplayObjects(listName, (EntityItemID)id);
} else if (itemType == "overlay") {
return addToGameplayObjects(listName, (OverlayID)id);
}
return false;
}
bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) {
if (itemType == "avatar") {
return removeFromGameplayObjects(listName, (QUuid)id);
} else if (itemType == "entity") {
} else if (itemType == "entity" || itemType == "overlay") {
return removeFromGameplayObjects(listName, (EntityItemID)id);
} else if (itemType == "overlay") {
return removeFromGameplayObjects(listName, (OverlayID)id);
}
return false;
}
@ -253,12 +235,6 @@ void SelectionScriptingInterface::printList(const QString& listName) {
qDebug() << j << ';';
}
qDebug() << "";
qDebug() << "Overlay IDs:";
for (auto k : (*currentList).getOverlayIDs()) {
qDebug() << k << ';';
}
qDebug() << "";
}
else {
qDebug() << "List named " << listName << " empty";
@ -272,7 +248,6 @@ void SelectionScriptingInterface::printList(const QString& listName) {
* @typedef {object} Selection.SelectedItemsList
* @property {Uuid[]} avatars - The IDs of the avatars in the selection.
* @property {Uuid[]} entities - The IDs of the entities in the selection.
* @property {Uuid[]} overlays - The IDs of the overlays in the selection.
*/
QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& listName) const {
QReadLocker lock(&_selectionListsLock);
@ -281,7 +256,6 @@ QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& lis
if (currentList != _selectedItemsListMap.end()) {
QList<QVariant> avatarIDs;
QList<QVariant> entityIDs;
QList<QVariant> overlayIDs;
if ((*currentList).getContainsData()) {
if (!(*currentList).getAvatarIDs().empty()) {
@ -294,15 +268,9 @@ QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& lis
entityIDs.push_back((QUuid)j );
}
}
if (!(*currentList).getOverlayIDs().empty()) {
for (auto j : (*currentList).getOverlayIDs()) {
overlayIDs.push_back((QUuid)j);
}
}
}
list["avatars"] = (avatarIDs);
list["entities"] = (entityIDs);
list["overlays"] = (overlayIDs);
return list;
}
@ -379,7 +347,6 @@ void SelectionToSceneHandler::updateSceneFromSelectedList() {
render::ItemIDs finalList;
render::ItemID currentID;
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
auto& overlays = qApp->getOverlays();
for (QUuid& currentAvatarID : thisList.getAvatarIDs()) {
auto avatar = std::static_pointer_cast<Avatar>(DependencyManager::get<AvatarManager>()->getAvatarBySessionID(currentAvatarID));
@ -398,16 +365,6 @@ void SelectionToSceneHandler::updateSceneFromSelectedList() {
}
}
for (OverlayID& currentOverlayID : thisList.getOverlayIDs()) {
auto overlay = overlays.getOverlay(currentOverlayID);
if (overlay != NULL) {
currentID = overlay->getRenderItemID();
if (currentID != render::Item::INVALID_ITEM_ID) {
finalList.push_back(currentID);
}
}
}
render::Selection selection(_listName.toStdString(), finalList);
transaction.resetSelection(selection);

View file

@ -19,7 +19,6 @@
#include <AbstractViewStateInterface.h>
#include "RenderableEntityItem.h"
#include "ui/overlays/Overlay.h"
#include <avatar/AvatarManager.h>
#include <render/HighlightStyle.h>
@ -37,15 +36,10 @@ public:
bool addToGameplayObjects(const EntityItemID& entityID);
bool removeFromGameplayObjects(const EntityItemID& entityID);
std::vector<OverlayID> getOverlayIDs() const { return _overlayIDs; }
bool addToGameplayObjects(const OverlayID& overlayID);
bool removeFromGameplayObjects(const OverlayID& overlayID);
private:
bool containsData { false };
std::vector<QUuid> _avatarIDs;
std::vector<EntityItemID> _entityIDs;
std::vector<OverlayID> _overlayIDs;
};
@ -83,11 +77,12 @@ protected:
};
/**jsdoc
* The <code>Selection</code> API provides a means of grouping together avatars, entities, and overlays in named lists.
* The <code>Selection</code> API provides a means of grouping together avatars and entities in named lists.
* @namespace Selection
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @example <caption>Outline an entity when it is grabbed by a controller.</caption>
* // Create a box and copy the following text into the entity's "Script URL" field.
@ -174,14 +169,14 @@ public:
Q_INVOKABLE bool clearSelectedItemsList(const QString& listName);
/**jsdoc
* Print out the list of avatars, entities, and overlays in a selection to the <em>debug log</em> (not the script log).
* Print out the list of avatars and entities in a selection to the <em>debug log</em> (not the script log).
* @function Selection.printList
* @param {string} listName - The name of the selection list.
*/
Q_INVOKABLE void printList(const QString& listName);
/**jsdoc
* Get the list of avatars, entities, and overlays stored in a selection list.
* Get the list of avatars and entities stored in a selection list.
* @function Selection.getSelectedItemsList
* @param {string} listName - The name of the selection list.
* @returns {Selection.SelectedItemsList} The content of a selection list. If the list name doesn't exist, the function

View file

@ -21,6 +21,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class SettingsScriptingInterface : public QObject {

View file

@ -34,6 +34,7 @@ public:
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} walletStatus
* @property {bool} limitedCommerce

View file

@ -31,6 +31,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} innerWidth - The width of the drawable area of the Interface window (i.e., without borders or other
* chrome), in pixels. <em>Read-only.</em>

View file

@ -90,7 +90,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
PROFILE_RANGE(app, __FUNCTION__);
PROFILE_RANGE(render, __FUNCTION__);
if (!_uiTexture) {
_uiTexture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda());
@ -119,7 +119,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
PROFILE_RANGE(app, __FUNCTION__);
PROFILE_RANGE(render, __FUNCTION__);
gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -134,9 +134,7 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
batch.resetViewTransform();
// Render all of the Script based "HUD" aka 2D overlays.
// note: we call them HUD, as opposed to 2D, only because there are some cases of 3D HUD overlays, like the
// cameral controls for the edit.js
qApp->getOverlays().renderHUD(renderArgs);
qApp->getOverlays().render(renderArgs);
}
void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
@ -178,7 +176,7 @@ static const auto DEFAULT_SAMPLER = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LI
static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
void ApplicationOverlay::buildFramebufferObject() {
PROFILE_RANGE(app, __FUNCTION__);
PROFILE_RANGE(render, __FUNCTION__);
auto uiSize = glm::uvec2(qApp->getUiSize());
if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) {

View file

@ -29,6 +29,7 @@ class AvatarInputs : public QObject {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {boolean} cameraEnabled <em>Read-only.</em>
* @property {boolean} cameraMuted <em>Read-only.</em>

View file

@ -57,7 +57,7 @@ void DialogsManager::showAddressBar() {
if (!hmd->getShouldShowTablet()) {
hmd->openTablet();
}
qApp->setKeyboardFocusOverlay(hmd->getCurrentTabletScreenID());
qApp->setKeyboardFocusEntity(hmd->getCurrentTabletScreenID());
setAddressBarVisible(true);
}
@ -70,7 +70,7 @@ void DialogsManager::hideAddressBar() {
tablet->gotoHomeScreen();
hmd->closeTablet();
}
qApp->setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
qApp->setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setAddressBarVisible(false);
}

View file

@ -33,11 +33,6 @@
#include <RegisteredMetaTypes.h>
#include <ui/TabletScriptingInterface.h>
#include "ui/overlays/Overlays.h"
#include "ui/overlays/Overlay.h"
#include "ui/overlays/ModelOverlay.h"
#include "ui/overlays/Cube3DOverlay.h"
#include "ui/overlays/Text3DOverlay.h"
#include "avatar/AvatarManager.h"
#include "avatar/MyAvatar.h"
#include "avatar/AvatarManager.h"
@ -120,21 +115,21 @@ std::pair<glm::vec3, glm::quat> calculateKeyboardPositionAndOrientation() {
float sensorToWorldScale = myAvatar->getSensorToWorldScale();
QUuid tabletID = hmd->getCurrentTabletFrameID();
if (!tabletID.isNull() && hmd->getShouldShowTablet()) {
Overlays& overlays = qApp->getOverlays();
auto tabletOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(tabletID));
if (tabletOverlay) {
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
bool landscapeMode = tablet->getLandscape();
glm::vec3 keyboardOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_OFFSET : KEYBOARD_TABLET_OFFSET;
glm::vec3 keyboardDegreesOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_DEGREES_OFFSET : KEYBOARD_TABLET_DEGREES_OFFSET;
glm::vec3 tabletWorldPosition = tabletOverlay->getWorldPosition();
glm::quat tabletWorldOrientation = tabletOverlay->getWorldOrientation();
glm::vec3 scaledKeyboardTabletOffset = keyboardOffset * sensorToWorldScale;
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(tabletID, desiredProperties);
keyboardLocation.first = tabletWorldPosition + (tabletWorldOrientation * scaledKeyboardTabletOffset);
keyboardLocation.second = tabletWorldOrientation * glm::quat(glm::radians(keyboardDegreesOffset));
}
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
bool landscapeMode = tablet->getLandscape();
glm::vec3 keyboardOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_OFFSET : KEYBOARD_TABLET_OFFSET;
glm::vec3 keyboardDegreesOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_DEGREES_OFFSET : KEYBOARD_TABLET_DEGREES_OFFSET;
glm::vec3 tabletWorldPosition = properties.getPosition();
glm::quat tabletWorldOrientation = properties.getRotation();
glm::vec3 scaledKeyboardTabletOffset = keyboardOffset * sensorToWorldScale;
keyboardLocation.first = tabletWorldPosition + (tabletWorldOrientation * scaledKeyboardTabletOffset);
keyboardLocation.second = tabletWorldOrientation * glm::quat(glm::radians(keyboardDegreesOffset));
} else {
glm::vec3 avatarWorldPosition = myAvatar->getWorldPosition();
glm::quat avatarWorldOrientation = myAvatar->getWorldOrientation();
@ -148,31 +143,27 @@ std::pair<glm::vec3, glm::quat> calculateKeyboardPositionAndOrientation() {
}
void Key::saveDimensionsAndLocalPosition() {
Overlays& overlays = qApp->getOverlays();
auto model3DOverlay = std::dynamic_pointer_cast<ModelOverlay>(overlays.getOverlay(_keyID));
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_DIMENSIONS;
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(_keyID, desiredProperties);
if (model3DOverlay) {
_originalLocalPosition = model3DOverlay->getLocalPosition();
_originalDimensions = model3DOverlay->getDimensions();
_currentLocalPosition = _originalLocalPosition;
}
_originalLocalPosition = properties.getLocalPosition();
_originalDimensions = properties.getDimensions();
_currentLocalPosition = _originalLocalPosition;
_originalDimensionsAndLocalPositionSaved = true;
}
void Key::scaleKey(float sensorToWorldScale) {
Overlays& overlays = qApp->getOverlays();
auto model3DOverlay = std::dynamic_pointer_cast<ModelOverlay>(overlays.getOverlay(_keyID));
if (model3DOverlay) {
if (_originalDimensionsAndLocalPositionSaved) {
glm::vec3 scaledLocalPosition = _originalLocalPosition * sensorToWorldScale;
glm::vec3 scaledDimensions = _originalDimensions * sensorToWorldScale;
_currentLocalPosition = scaledLocalPosition;
QVariantMap properties {
{ "dimensions", vec3toVariant(scaledDimensions) },
{ "localPosition", vec3toVariant(scaledLocalPosition) }
};
overlays.editOverlay(_keyID, properties);
EntityItemProperties properties;
properties.setDimensions(scaledDimensions);
properties.setLocalPosition(scaledLocalPosition);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_keyID, properties);
}
}
@ -241,6 +232,18 @@ void Keyboard::registerKeyboardHighlighting() {
selection->enableListToScene(KEY_PRESSED_HIGHLIGHT);
}
void Keyboard::disableSelectionLists() {
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->disableListHighlight(KEY_HOVER_HIGHLIGHT);
selection->disableListHighlight(KEY_PRESSED_HIGHLIGHT);
}
void Keyboard::enableSelectionLists() {
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->enableListHighlight(KEY_HOVER_HIGHLIGHT, KEY_HOVERING_STYLE);
selection->enableListHighlight(KEY_PRESSED_HIGHLIGHT, KEY_PRESSING_STYLE);
}
bool Keyboard::getUse3DKeyboard() const {
return _use3DKeyboardLock.resultWithReadLock<bool>([&] {
return _use3DKeyboard.get();
@ -262,21 +265,21 @@ void Keyboard::createKeyboard() {
QVariantMap leftStylusProperties {
{ "hand", LEFT_HAND_CONTROLLER_INDEX },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "model", modelProperties },
{ "tipOffset", vec3toVariant(MALLET_TIP_OFFSET) }
};
QVariantMap rightStylusProperties {
{ "hand", RIGHT_HAND_CONTROLLER_INDEX },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "model", modelProperties },
{ "tipOffset", vec3toVariant(MALLET_TIP_OFFSET) }
};
_leftHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(leftStylusProperties, StylusPointer::buildStylusOverlay(leftStylusProperties), true, true,
_leftHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(leftStylusProperties, StylusPointer::buildStylus(leftStylusProperties), true, true,
MALLET_POSITION_OFFSET, MALLET_ROTATION_OFFSET, MALLET_MODEL_DIMENSIONS));
_rightHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(rightStylusProperties, StylusPointer::buildStylusOverlay(rightStylusProperties), true, true,
_rightHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(rightStylusProperties, StylusPointer::buildStylus(rightStylusProperties), true, true,
MALLET_POSITION_OFFSET, MALLET_ROTATION_OFFSET, MALLET_MODEL_DIMENSIONS));
pointerManager->disablePointer(_rightHandStylus);
@ -300,6 +303,7 @@ void Keyboard::setRaised(bool raised) {
raiseKeyboardAnchor(raised);
raiseKeyboard(raised);
raised ? enableStylus() : disableStylus();
raised ? enableSelectionLists() : disableSelectionLists();
withWriteLock([&] {
_raised = raised;
_layerIndex = 0;
@ -312,93 +316,65 @@ void Keyboard::setRaised(bool raised) {
}
void Keyboard::updateTextDisplay() {
Overlays& overlays = qApp->getOverlays();
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
float sensorToWorldScale = myAvatar->getSensorToWorldScale();
float textWidth = (float) overlays.textSize(_textDisplay.overlayID, _typedCharacters).width();
float textWidth = (float)entityScriptingInterface->textSize(_textDisplay.entityID, _typedCharacters).width();
glm::vec3 scaledDimensions = _textDisplay.dimensions;
scaledDimensions *= sensorToWorldScale;
float leftMargin = (scaledDimensions.x / 2);
scaledDimensions.x += textWidth;
scaledDimensions.y *= 1.25f;
QVariantMap textDisplayProperties {
{ "dimensions", vec3toVariant(scaledDimensions) },
{ "leftMargin", leftMargin },
{ "text", _typedCharacters },
{ "lineHeight", (_textDisplay.lineHeight * sensorToWorldScale) }
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
EntityItemProperties properties;
properties.setDimensions(scaledDimensions);
properties.setLeftMargin(leftMargin);
properties.setText(_typedCharacters);
properties.setLineHeight(_textDisplay.lineHeight * sensorToWorldScale);
entityScriptingInterface->editEntity(_textDisplay.entityID, properties);
}
void Keyboard::raiseKeyboardAnchor(bool raise) const {
Overlays& overlays = qApp->getOverlays();
OverlayID anchorOverlayID = _anchor.overlayID;
auto anchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(anchorOverlayID));
if (anchorOverlay) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityItemProperties properties;
properties.setVisible(raise);
entityScriptingInterface->editEntity(_textDisplay.entityID, properties);
entityScriptingInterface->editEntity(_backPlate.entityID, properties);
if (_resetKeyboardPositionOnRaise) {
std::pair<glm::vec3, glm::quat> keyboardLocation = calculateKeyboardPositionAndOrientation();
if (_resetKeyboardPositionOnRaise) {
anchorOverlay->setWorldPosition(keyboardLocation.first);
anchorOverlay->setWorldOrientation(keyboardLocation.second);
}
anchorOverlay->setVisible(raise);
QVariantMap textDisplayProperties {
{ "visible", raise }
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
auto backPlateOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(_backPlate.overlayID));
if (backPlateOverlay) {
backPlateOverlay->setVisible(raise);
}
properties.setPosition(keyboardLocation.first);
properties.setRotation(keyboardLocation.second);
}
entityScriptingInterface->editEntity(_anchor.entityID, properties);
}
void Keyboard::scaleKeyboard(float sensorToWorldScale) {
Overlays& overlays = qApp->getOverlays();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
glm::vec3 scaledDimensions = _anchor.originalDimensions * sensorToWorldScale;
auto volume3DOverlay = std::dynamic_pointer_cast<Volume3DOverlay>(overlays.getOverlay(_anchor.overlayID));
if (volume3DOverlay) {
volume3DOverlay->setDimensions(scaledDimensions);
{
EntityItemProperties properties;
properties.setLocalPosition(_backPlate.localPosition * sensorToWorldScale);
properties.setDimensions(_backPlate.dimensions * sensorToWorldScale);
entityScriptingInterface->editEntity(_backPlate.entityID, properties);
}
for (auto& keyboardLayer: _keyboardLayers) {
for (auto& keyboardLayer : _keyboardLayers) {
for (auto iter = keyboardLayer.begin(); iter != keyboardLayer.end(); iter++) {
iter.value().scaleKey(sensorToWorldScale);
}
}
glm::vec3 scaledLocalPosition = _textDisplay.localPosition * sensorToWorldScale;
glm::vec3 textDisplayScaledDimensions = _textDisplay.dimensions * sensorToWorldScale;
QVariantMap textDisplayProperties {
{ "localPosition", vec3toVariant(scaledLocalPosition) },
{ "dimensions", vec3toVariant(textDisplayScaledDimensions) },
{ "lineHeight", (_textDisplay.lineHeight * sensorToWorldScale) }
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
glm::vec3 backPlateScaledDimensions = _backPlate.dimensions * sensorToWorldScale;
glm::vec3 backPlateScaledLocalPosition = _backPlate.localPosition * sensorToWorldScale;
QVariantMap backPlateProperties {
{ "localPosition", vec3toVariant(backPlateScaledLocalPosition) },
{ "dimensions", vec3toVariant(backPlateScaledDimensions) }
};
overlays.editOverlay(_backPlate.overlayID, backPlateProperties);
{
EntityItemProperties properties;
properties.setLocalPosition(_textDisplay.localPosition * sensorToWorldScale);
properties.setDimensions(_textDisplay.dimensions * sensorToWorldScale);
properties.setLineHeight(_textDisplay.lineHeight * sensorToWorldScale);
entityScriptingInterface->editEntity(_textDisplay.entityID, properties);
}
}
void Keyboard::startLayerSwitchTimer() {
@ -419,13 +395,12 @@ void Keyboard::raiseKeyboard(bool raise) const {
if (_keyboardLayers.empty()) {
return;
}
Overlays& overlays = qApp->getOverlays();
const auto& keyboardLayer = _keyboardLayers[_layerIndex];
EntityItemProperties properties;
properties.setVisible(raise);
for (auto iter = keyboardLayer.begin(); iter != keyboardLayer.end(); iter++) {
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(iter.key()));
if (base3DOverlay) {
base3DOverlay->setVisible(raise);
}
DependencyManager::get<EntityScriptingInterface>()->editEntity(iter.key(), properties);
}
}
@ -465,19 +440,15 @@ bool Keyboard::getPreferMalletsOverLasers() const {
}
void Keyboard::switchToLayer(int layerIndex) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (layerIndex >= 0 && layerIndex < (int)_keyboardLayers.size()) {
Overlays& overlays = qApp->getOverlays();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
auto oldProperties = entityScriptingInterface->getEntityProperties(_anchor.entityID, desiredProperties);
OverlayID currentAnchorOverlayID = _anchor.overlayID;
glm::vec3 currentOverlayPosition;
glm::quat currentOverlayOrientation;
auto currentAnchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(currentAnchorOverlayID));
if (currentAnchorOverlay) {
currentOverlayPosition = currentAnchorOverlay->getWorldPosition();
currentOverlayOrientation = currentAnchorOverlay->getWorldOrientation();
}
glm::vec3 currentPosition = oldProperties.getPosition();
glm::quat currentOrientation = oldProperties.getRotation();
raiseKeyboardAnchor(false);
raiseKeyboard(false);
@ -487,19 +458,17 @@ void Keyboard::switchToLayer(int layerIndex) {
raiseKeyboardAnchor(true);
raiseKeyboard(true);
OverlayID newAnchorOverlayID = _anchor.overlayID;
auto newAnchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(newAnchorOverlayID));
if (newAnchorOverlay) {
newAnchorOverlay->setWorldPosition(currentOverlayPosition);
newAnchorOverlay->setWorldOrientation(currentOverlayOrientation);
}
EntityItemProperties properties;
properties.setPosition(currentPosition);
properties.setRotation(currentOrientation);
entityScriptingInterface->editEntity(_anchor.entityID, properties);
startLayerSwitchTimer();
}
}
bool Keyboard::shouldProcessOverlayAndPointerEvent(const PointerEvent& event, const OverlayID& overlayID) const {
return (shouldProcessPointerEvent(event) && shouldProcessOverlay(overlayID));
bool Keyboard::shouldProcessEntityAndPointerEvent(const PointerEvent& event) const {
return (shouldProcessPointerEvent(event) && shouldProcessEntity());
}
bool Keyboard::shouldProcessPointerEvent(const PointerEvent& event) const {
@ -510,14 +479,14 @@ bool Keyboard::shouldProcessPointerEvent(const PointerEvent& event) const {
return ((isStylusEvent && preferMalletsOverLasers) || (isLaserEvent && !preferMalletsOverLasers));
}
void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event) {
void Keyboard::handleTriggerBegin(const QUuid& id, const PointerEvent& event) {
auto buttonType = event.getButton();
if (!shouldProcessOverlayAndPointerEvent(event, overlayID) || buttonType != PointerEvent::PrimaryButton) {
if (!shouldProcessEntityAndPointerEvent(event) || buttonType != PointerEvent::PrimaryButton) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
@ -533,13 +502,9 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->triggerHapticPulse(PULSE_STRENGTH, PULSE_DURATION, handIndex);
Overlays& overlays = qApp->getOverlays();
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
glm::vec3 keyWorldPosition;
if (base3DOverlay) {
keyWorldPosition = base3DOverlay->getWorldPosition();
}
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
glm::vec3 keyWorldPosition = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id, desiredProperties).getPosition();
AudioInjectorOptions audioOptions;
audioOptions.localOnly = true;
@ -601,7 +566,7 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent
key.startTimer(KEY_PRESS_TIMEOUT_MS);
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->addToSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "overlay", overlayID);
selection->addToSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "entity", id);
}
}
@ -617,25 +582,23 @@ void Keyboard::setRightHandLaser(unsigned int rightHandLaser) {
});
}
void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleTriggerEnd(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
Key& key = search.value();;
Overlays& overlays = qApp->getOverlays();
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
Key& key = search.value();
if (base3DOverlay) {
base3DOverlay->setLocalPosition(key.getCurrentLocalPosition());
}
EntityItemProperties properties;
properties.setLocalPosition(key.getCurrentLocalPosition());
DependencyManager::get<EntityScriptingInterface>()->editEntity(id, properties);
key.setIsPressed(false);
if (key.timerFinished() && getPreferMalletsOverLasers()) {
@ -643,78 +606,79 @@ void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent&
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->removeFromSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "overlay", overlayID);
selection->removeFromSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "entity", id);
}
void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleTriggerContinue(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
Key& key = search.value();
Overlays& overlays = qApp->getOverlays();
if (!key.isPressed() && getPreferMalletsOverLasers()) {
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
unsigned int pointerID = event.getID();
auto pointerManager = DependencyManager::get<PointerManager>();
auto pickResult = pointerManager->getPrevPickResult(pointerID);
auto stylusPickResult = std::dynamic_pointer_cast<StylusPickResult>(pickResult);
float distance = stylusPickResult->distance;
if (base3DOverlay) {
unsigned int pointerID = event.getID();
auto pointerManager = DependencyManager::get<PointerManager>();
auto pickResult = pointerManager->getPrevPickResult(pointerID);
auto stylusPickResult = std::dynamic_pointer_cast<StylusPickResult>(pickResult);
float distance = stylusPickResult->distance;
static const float PENETRATION_THRESHOLD = 0.025f;
if (distance < PENETRATION_THRESHOLD) {
static const float Z_OFFSET = 0.002f;
static const float PENATRATION_THRESHOLD = 0.025f;
if (distance < PENATRATION_THRESHOLD) {
static const float Z_OFFSET = 0.002f;
glm::quat overlayOrientation = base3DOverlay->getWorldOrientation();
glm::vec3 overlayYAxis = overlayOrientation * Z_AXIS;
glm::vec3 overlayYOffset = overlayYAxis * Z_OFFSET;
glm::vec3 localPosition = key.getCurrentLocalPosition() - overlayYOffset;
base3DOverlay->setLocalPosition(localPosition);
key.setIsPressed(true);
}
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ROTATION;
glm::quat orientation = entityScriptingInterface->getEntityProperties(id, desiredProperties).getRotation();
glm::vec3 yAxis = orientation * Z_AXIS;
glm::vec3 yOffset = yAxis * Z_OFFSET;
glm::vec3 localPosition = key.getCurrentLocalPosition() - yOffset;
EntityItemProperties properties;
properties.setLocalPosition(localPosition);
entityScriptingInterface->editEntity(id, properties);
key.setIsPressed(true);
}
}
}
void Keyboard::handleHoverBegin(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleHoverBegin(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->addToSelectedItemsList(KEY_HOVER_HIGHLIGHT, "overlay", overlayID);
selection->addToSelectedItemsList(KEY_HOVER_HIGHLIGHT, "entity", id);
}
void Keyboard::handleHoverEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleHoverEnd(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->removeFromSelectedItemsList(KEY_HOVER_HIGHLIGHT, "overlay", overlayID);
selection->removeFromSelectedItemsList(KEY_HOVER_HIGHLIGHT, "entity", id);
}
void Keyboard::disableStylus() {
@ -752,7 +716,6 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
}
clearKeyboardKeys();
Overlays& overlays = qApp->getOverlays();
auto requestData = request->getData();
QVector<QUuid> includeItems;
@ -776,54 +739,60 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
return;
}
QVariantMap anchorProperties {
{ "name", "KeyboardAnchor"},
{ "isSolid", true },
{ "visible", false },
{ "grabbable", true },
{ "ignorePickIntersection", false },
{ "dimensions", anchorObject["dimensions"].toVariant() },
{ "position", anchorObject["position"].toVariant() },
{ "orientation", anchorObject["rotation"].toVariant() }
};
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
{
glm::vec3 dimensions = vec3FromVariant(anchorObject["dimensions"].toVariant());
glm::vec3 dimensions = vec3FromVariant(anchorObject["dimensions"].toVariant());
EntityItemProperties properties;
properties.setType(EntityTypes::Box);
properties.setName("KeyboardAnchor");
properties.setVisible(false);
properties.getGrab().setGrabbable(true);
properties.setIgnorePickIntersection(false);
properties.setDimensions(dimensions);
properties.setPosition(vec3FromVariant(anchorObject["position"].toVariant()));
properties.setRotation(quatFromVariant(anchorObject["rotation"].toVariant()));
Anchor anchor;
anchor.overlayID = overlays.addOverlay("cube", anchorProperties);
anchor.originalDimensions = dimensions;
_anchor = anchor;
Anchor anchor;
anchor.entityID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
anchor.originalDimensions = dimensions;
_anchor = anchor;
}
QJsonObject backPlateObject = jsonObject["backPlate"].toObject();
{
QJsonObject backPlateObject = jsonObject["backPlate"].toObject();
glm::vec3 position = vec3FromVariant(backPlateObject["position"].toVariant());
glm::vec3 dimensions = vec3FromVariant(backPlateObject["dimensions"].toVariant());
glm::quat rotation = quatFromVariant(backPlateObject["rotation"].toVariant());
QVariantMap backPlateProperties {
{ "name", "backPlate"},
{ "isSolid", true },
{ "visible", true },
{ "grabbable", false },
{ "alpha", 0.0 },
{ "ignoreRayIntersection", false},
{ "dimensions", backPlateObject["dimensions"].toVariant() },
{ "position", backPlateObject["position"].toVariant() },
{ "orientation", backPlateObject["rotation"].toVariant() },
{ "parentID", _anchor.overlayID }
};
EntityItemProperties properties;
properties.setType(EntityTypes::Box);
properties.setName("Keyboard-BackPlate");
properties.setVisible(true);
properties.getGrab().setGrabbable(false);
properties.setAlpha(0.0f);
properties.setIgnorePickIntersection(false);
properties.setDimensions(dimensions);
properties.setPosition(position);
properties.setRotation(rotation);
properties.setParentID(_anchor.entityID);
BackPlate backPlate;
backPlate.overlayID = overlays.addOverlay("cube", backPlateProperties);
backPlate.dimensions = vec3FromVariant(backPlateObject["dimensions"].toVariant());
backPlate.localPosition = vec3FromVariant(overlays.getProperty(backPlate.overlayID, "localPosition").value);
_backPlate = backPlate;
BackPlate backPlate;
backPlate.entityID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
backPlate.dimensions = dimensions;
glm::quat anchorEntityInverseWorldOrientation = glm::inverse(rotation);
glm::vec3 anchorEntityLocalTranslation = anchorEntityInverseWorldOrientation * -position;
backPlate.localPosition = (anchorEntityInverseWorldOrientation * position) + anchorEntityLocalTranslation;
_backPlate = backPlate;
}
const QJsonArray& keyboardLayers = jsonObject["layers"].toArray();
int keyboardLayerCount = keyboardLayers.size();
_keyboardLayers.reserve(keyboardLayerCount);
for (int keyboardLayerIndex = 0; keyboardLayerIndex < keyboardLayerCount; keyboardLayerIndex++) {
const QJsonValue& keyboardLayer = keyboardLayers[keyboardLayerIndex].toArray();
QHash<OverlayID, Key> keyboardLayerKeys;
QHash<QUuid, Key> keyboardLayerKeys;
foreach (const QJsonValue& keyboardKeyValue, keyboardLayer.toArray()) {
QVariantMap textureMap;
@ -841,20 +810,18 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
QString modelUrl = keyboardKeyValue["modelURL"].toString();
QString url = (useResourcePath ? (resourcePath + modelUrl) : modelUrl);
QVariantMap properties {
{ "dimensions", keyboardKeyValue["dimensions"].toVariant() },
{ "position", keyboardKeyValue["position"].toVariant() },
{ "visible", false },
{ "isSolid", true },
{ "emissive", true },
{ "parentID", _anchor.overlayID },
{ "url", url },
{ "textures", textureMap },
{ "grabbable", false },
{ "localOrientation", keyboardKeyValue["localOrientation"].toVariant() }
};
OverlayID overlayID = overlays.addOverlay("model", properties);
EntityItemProperties properties;
properties.setType(EntityTypes::Model);
properties.setDimensions(vec3FromVariant(keyboardKeyValue["dimensions"].toVariant()));
properties.setPosition(vec3FromVariant(keyboardKeyValue["position"].toVariant()));
properties.setVisible(false);
properties.setEmissive(true);
properties.setParentID(_anchor.entityID);
properties.setModelURL(url);
properties.setTextures(QString(QJsonDocument::fromVariant(textureMap).toJson()));
properties.getGrab().setGrabbable(false);
properties.setLocalRotation(quatFromVariant(keyboardKeyValue["localOrientation"].toVariant()));
QUuid id = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
QString keyType = keyboardKeyValue["type"].toString();
QString keyString = keyboardKeyValue["key"].toString();
@ -869,48 +836,54 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
key.setSwitchToLayerIndex(switchToLayer);
}
}
key.setID(overlayID);
key.setID(id);
key.setKeyString(keyString);
key.saveDimensionsAndLocalPosition();
includeItems.append(key.getID());
_itemsToIgnore.append(key.getID());
keyboardLayerKeys.insert(overlayID, key);
_itemsToIgnore.insert(key.getID());
keyboardLayerKeys.insert(id, key);
}
_keyboardLayers.push_back(keyboardLayerKeys);
}
TextDisplay textDisplay;
QJsonObject displayTextObject = jsonObject["textDisplay"].toObject();
{
QJsonObject displayTextObject = jsonObject["textDisplay"].toObject();
glm::vec3 dimensions = vec3FromVariant(displayTextObject["dimensions"].toVariant());
glm::vec3 localPosition = vec3FromVariant(displayTextObject["localPosition"].toVariant());
float lineHeight = (float)displayTextObject["lineHeight"].toDouble();
QVariantMap displayTextProperties {
{ "dimensions", displayTextObject["dimensions"].toVariant() },
{ "localPosition", displayTextObject["localPosition"].toVariant() },
{ "localOrientation", displayTextObject["localOrientation"].toVariant() },
{ "leftMargin", displayTextObject["leftMargin"].toVariant() },
{ "rightMargin", displayTextObject["rightMargin"].toVariant() },
{ "topMargin", displayTextObject["topMargin"].toVariant() },
{ "bottomMargin", displayTextObject["bottomMargin"].toVariant() },
{ "lineHeight", displayTextObject["lineHeight"].toVariant() },
{ "visible", false },
{ "emissive", true },
{ "grabbable", false },
{ "text", ""},
{ "parentID", _anchor.overlayID }
};
EntityItemProperties properties;
properties.setType(EntityTypes::Text);
properties.setDimensions(dimensions);
properties.setLocalPosition(localPosition);
properties.setLocalRotation(quatFromVariant(displayTextObject["localOrientation"].toVariant()));
properties.setLeftMargin((float)displayTextObject["leftMargin"].toDouble());
properties.setRightMargin((float)displayTextObject["rightMargin"].toDouble());
properties.setTopMargin((float)displayTextObject["topMargin"].toDouble());
properties.setBottomMargin((float)displayTextObject["bottomMargin"].toDouble());
properties.setLineHeight((float)displayTextObject["lineHeight"].toDouble());
properties.setVisible(false);
properties.setEmissive(true);
properties.getGrab().setGrabbable(false);
properties.setText("");
properties.setTextAlpha(1.0f);
properties.setBackgroundAlpha(0.7f);
properties.setParentID(_anchor.entityID);
textDisplay.overlayID = overlays.addOverlay("text3d", displayTextProperties);
textDisplay.localPosition = vec3FromVariant(displayTextObject["localPosition"].toVariant());
textDisplay.dimensions = vec3FromVariant(displayTextObject["dimensions"].toVariant());
textDisplay.lineHeight = (float) displayTextObject["lineHeight"].toDouble();
_textDisplay = textDisplay;
TextDisplay textDisplay;
textDisplay.entityID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
textDisplay.localPosition = localPosition;
textDisplay.dimensions = dimensions;
textDisplay.lineHeight = lineHeight;
_textDisplay = textDisplay;
}
_ignoreItemsLock.withWriteLock([&] {
_itemsToIgnore.append(_textDisplay.overlayID);
_itemsToIgnore.append(_anchor.overlayID);
_itemsToIgnore.insert(_textDisplay.entityID);
_itemsToIgnore.insert(_anchor.entityID);
});
_layerIndex = 0;
auto pointerManager = DependencyManager::get<PointerManager>();
@ -922,34 +895,33 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
}
OverlayID Keyboard::getAnchorID() {
return _ignoreItemsLock.resultWithReadLock<OverlayID>([&] {
return _anchor.overlayID;
QUuid Keyboard::getAnchorID() {
return _ignoreItemsLock.resultWithReadLock<QUuid>([&] {
return _anchor.entityID;
});
}
bool Keyboard::shouldProcessOverlay(const OverlayID& overlayID) const {
return (!_keyboardLayers.empty() && isLayerSwitchTimerFinished() && overlayID != _backPlate.overlayID);
bool Keyboard::shouldProcessEntity() const {
return (!_keyboardLayers.empty() && isLayerSwitchTimerFinished());
}
QVector<OverlayID> Keyboard::getKeysID() {
return _ignoreItemsLock.resultWithReadLock<QVector<OverlayID>>([&] {
QSet<QUuid> Keyboard::getKeyIDs() {
return _ignoreItemsLock.resultWithReadLock<QSet<QUuid>>([&] {
return _itemsToIgnore;
});
}
void Keyboard::clearKeyboardKeys() {
Overlays& overlays = qApp->getOverlays();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
for (const auto& keyboardLayer: _keyboardLayers) {
for (auto iter = keyboardLayer.begin(); iter != keyboardLayer.end(); iter++) {
overlays.deleteOverlay(iter.key());
entityScriptingInterface->deleteEntity(iter.key());
}
}
overlays.deleteOverlay(_anchor.overlayID);
overlays.deleteOverlay(_textDisplay.overlayID);
overlays.deleteOverlay(_backPlate.overlayID);
entityScriptingInterface->deleteEntity(_anchor.entityID);
entityScriptingInterface->deleteEntity(_textDisplay.entityID);
entityScriptingInterface->deleteEntity(_backPlate.entityID);
_keyboardLayers.clear();
@ -989,8 +961,8 @@ void Keyboard::disableRightMallet() {
pointerManager->disablePointer(_rightHandStylus);
}
bool Keyboard::containsID(OverlayID overlayID) const {
bool Keyboard::containsID(const QUuid& id) const {
return resultWithReadLock<bool>([&] {
return _itemsToIgnore.contains(overlayID) || _backPlate.overlayID == overlayID;
return _itemsToIgnore.contains(id) || _backPlate.entityID == id;
});
}

View file

@ -25,8 +25,6 @@
#include <shared/ReadWriteLockable.h>
#include <SettingHandle.h>
#include "ui/overlays/Overlay.h"
class PointerEvent;
@ -47,8 +45,8 @@ public:
static Key::Type getKeyTypeFromString(const QString& keyTypeString);
OverlayID getID() const { return _keyID; }
void setID(OverlayID overlayID) { _keyID = overlayID; }
QUuid getID() const { return _keyID; }
void setID(const QUuid& id) { _keyID = id; }
void startTimer(int time);
bool timerFinished();
@ -77,12 +75,13 @@ private:
int _switchToLayer { 0 };
bool _pressed { false };
OverlayID _keyID;
QUuid _keyID;
QString _keyString;
glm::vec3 _originalLocalPosition;
glm::vec3 _originalDimensions;
glm::vec3 _currentLocalPosition;
bool _originalDimensionsAndLocalPositionSaved { false };
std::shared_ptr<QTimer> _timer { std::make_shared<QTimer>() };
};
@ -111,35 +110,35 @@ public:
bool getUse3DKeyboard() const;
void setUse3DKeyboard(bool use);
bool containsID(OverlayID overlayID) const;
bool containsID(const QUuid& id) const;
void loadKeyboardFile(const QString& keyboardFile);
QVector<OverlayID> getKeysID();
OverlayID getAnchorID();
QSet<QUuid> getKeyIDs();
QUuid getAnchorID();
public slots:
void handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event);
void handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event);
void handleTriggerContinue(const OverlayID& overlayID, const PointerEvent& event);
void handleHoverBegin(const OverlayID& overlayID, const PointerEvent& event);
void handleHoverEnd(const OverlayID& overlayID, const PointerEvent& event);
void handleTriggerBegin(const QUuid& id, const PointerEvent& event);
void handleTriggerEnd(const QUuid& id, const PointerEvent& event);
void handleTriggerContinue(const QUuid& id, const PointerEvent& event);
void handleHoverBegin(const QUuid& id, const PointerEvent& event);
void handleHoverEnd(const QUuid& id, const PointerEvent& event);
void scaleKeyboard(float sensorToWorldScale);
private:
struct Anchor {
OverlayID overlayID;
QUuid entityID;
glm::vec3 originalDimensions;
};
struct BackPlate {
OverlayID overlayID;
QUuid entityID;
glm::vec3 dimensions;
glm::vec3 localPosition;
};
struct TextDisplay {
float lineHeight;
OverlayID overlayID;
QUuid entityID;
glm::vec3 localPosition;
glm::vec3 dimensions;
};
@ -148,14 +147,16 @@ private:
void raiseKeyboardAnchor(bool raise) const;
void enableStylus();
void disableStylus();
void enableSelectionLists();
void disableSelectionLists();
void setLayerIndex(int layerIndex);
void clearKeyboardKeys();
void switchToLayer(int layerIndex);
void updateTextDisplay();
bool shouldProcessOverlayAndPointerEvent(const PointerEvent& event, const OverlayID& overlayID) const;
bool shouldProcessEntityAndPointerEvent(const PointerEvent& event) const;
bool shouldProcessPointerEvent(const PointerEvent& event) const;
bool shouldProcessOverlay(const OverlayID& overlayID) const;
bool shouldProcessEntity() const;
void startLayerSwitchTimer();
bool isLayerSwitchTimerFinished() const;
@ -184,8 +185,8 @@ private:
Anchor _anchor;
BackPlate _backPlate;
QVector<OverlayID> _itemsToIgnore;
std::vector<QHash<OverlayID, Key>> _keyboardLayers;
QSet<QUuid> _itemsToIgnore;
std::vector<QHash<QUuid, Key>> _keyboardLayers;
};
#endif

View file

@ -34,7 +34,7 @@
HIFI_QML_DEF(LoginDialog)
static const QUrl TABLET_LOGIN_DIALOG_URL("dialogs/TabletLoginDialog.qml");
const QUrl OVERLAY_LOGIN_DIALOG = PathUtils::qmlUrl("OverlayLoginDialog.qml");
const QUrl LOGIN_DIALOG = PathUtils::qmlUrl("OverlayLoginDialog.qml");
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
auto accountManager = DependencyManager::get<AccountManager>();
@ -71,7 +71,7 @@ void LoginDialog::showWithSelection() {
if (!qApp->getLoginDialogPoppedUp()) {
tablet->initialScreen(TABLET_LOGIN_DIALOG_URL);
} else {
qApp->createLoginDialogOverlay();
qApp->createLoginDialog();
}
}

View file

@ -18,7 +18,7 @@
class QNetworkReply;
extern const QUrl OVERLAY_LOGIN_DIALOG;
extern const QUrl LOGIN_DIALOG;
class LoginDialog : public OffscreenQmlDialog {
Q_OBJECT

View file

@ -42,6 +42,7 @@ private:
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class Snapshot : public QObject, public Dependency {

View file

@ -158,7 +158,7 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(rayPicksCount, totalPicks[PickQuery::Ray]);
STAT_UPDATE(parabolaPicksCount, totalPicks[PickQuery::Parabola]);
STAT_UPDATE(collisionPicksCount, totalPicks[PickQuery::Collision]);
std::vector<QVector4D> updatedPicks = pickManager->getUpdatedPickCounts();
std::vector<QVector3D> updatedPicks = pickManager->getUpdatedPickCounts();
STAT_UPDATE(stylusPicksUpdated, updatedPicks[PickQuery::Stylus]);
STAT_UPDATE(rayPicksUpdated, updatedPicks[PickQuery::Ray]);
STAT_UPDATE(parabolaPicksUpdated, updatedPicks[PickQuery::Parabola]);

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