History

Merge branch 'master' of https://github.com/highfidelity/hifi into project-freeloco

r3tk0n committed 7 years ago

Commit ebbf48a2 parents 0305877 051ab611002 files · +32726 −23541Browse files

Showing the changes to interface/src/Application.cpp (1 of 1002 files). Show all

Unified · Split

interface/src/Application.cpp+526−355
@@ -102,7 +102,7 @@ · 101 unmodified lines
102102 #include <MessagesClient.h>
103103 #include <hfm/ModelFormatRegistry.h>
104104 #include <model-networking/ModelCacheScriptingInterface.h>
105−#include <model-networking/TextureCacheScriptingInterface.h>
105+#include <material-networking/TextureCacheScriptingInterface.h>
106106 #include <ModelEntityItem.h>
107107 #include <NetworkAccessManager.h>
108108 #include <NetworkingConstants.h>
@@ -120,6 +120,7 @@ · 11 unmodified lines
120120 #include <plugins/PluginManager.h>
121121 #include <plugins/PluginUtils.h>
122122 #include <plugins/SteamClientPlugin.h>
123+#include <plugins/OculusPlatformPlugin.h>
123124 #include <plugins/InputConfiguration.h>
124125 #include <RecordingScriptingInterface.h>
125126 #include <render/EngineStats.h>
@@ -151,7 +152,9 @@ · 25 unmodified lines
151152 #include <trackers/EyeTracker.h>
152153 #include <avatars-renderer/ScriptAvatar.h>
153154 #include <RenderableEntityItem.h>
154−#include <model-networking/MaterialCache.h>
155+#include <RenderableTextEntityItem.h>
156+#include <RenderableWebEntityItem.h>
157+#include <material-networking/MaterialCache.h>
155158 #include "recording/ClipCache.h"
156159
157160 #include "AudioClient.h"
@@ -159,6 +162,7 @@ · 1 unmodified line
159162 #include "avatar/AvatarManager.h"
160163 #include "avatar/MyHead.h"
161164 #include "avatar/AvatarPackager.h"
165+#include "avatar/MyCharacterController.h"
162166 #include "CrashRecoveryHandler.h"
163167 #include "CrashHandler.h"
164168 #include "devices/DdeFaceTracker.h"
@@ -195,15 +199,12 @@ · 30 unmodified lines
195199 #include "ui/AvatarInputs.h"
196200 #include "ui/DialogsManager.h"
197201 #include "ui/LoginDialog.h"
198−#include "ui/overlays/Cube3DOverlay.h"
199−#include "ui/overlays/Web3DOverlay.h"
200202 #include "ui/Snapshot.h"
201203 #include "ui/SnapshotAnimated.h"
202204 #include "ui/StandAloneJSConsole.h"
203205 #include "ui/Stats.h"
204206 #include "ui/AnimStats.h"
205207 #include "ui/UpdateDialog.h"
206−#include "ui/overlays/Overlays.h"
207208 #include "ui/DomainConnectionModel.h"
208209 #include "ui/Keyboard.h"
209210 #include "Util.h"
@@ -232,6 +233,7 @@ · 22 unmodified lines
232233 #include "commerce/Ledger.h"
233234 #include "commerce/Wallet.h"
234235 #include "commerce/QmlCommerce.h"
236+#include "commerce/QmlMarketplace.h"
235237 #include "ResourceRequestObserver.h"
236238
237239 #include "webbrowser/WebBrowserSuggestionsEngine.h"
@@ -347,6 +349,8 @@ static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin"; · 109 unmodified lines
347349 static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
348350 static const QString KEEP_ME_LOGGED_IN_SETTING_NAME = "keepMeLoggedIn";
349351
352+static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
353+
350354 #if defined(Q_OS_ANDROID)
351355 static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt";
352356 #endif
@@ -599,8 +603,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt · 246 unmodified lines
599603 __android_log_write(ANDROID_LOG_FATAL,"Interface",local);
600604 abort();
601605 }
602−#endif
606+#else
603607 qApp->getLogger()->addMessage(qPrintable(logMessage));
608+#endif
604609 }
605610 }
606611
@@ -618,7 +623,7 @@ public: · 11 unmodified lines
618623 case NestableType::Entity:
619624 return getEntityModelProvider(static_cast<EntityItemID>(uuid));
620625 case NestableType::Overlay:
621− return getOverlayModelProvider(static_cast<OverlayID>(uuid));
626+ return nullptr;
622627 case NestableType::Avatar:
623628 return getAvatarModelProvider(uuid);
624629 }
@@ -642,22 +647,6 @@ private: · 17 unmodified lines
642647 return provider;
643648 }
644649
645− scriptable::ModelProviderPointer getOverlayModelProvider(OverlayID overlayID) {
646− scriptable::ModelProviderPointer provider;
647− auto &overlays = qApp->getOverlays();
648− if (auto overlay = overlays.getOverlay(overlayID)) {
649− if (auto base3d = std::dynamic_pointer_cast<Base3DOverlay>(overlay)) {
650− provider = std::dynamic_pointer_cast<scriptable::ModelProvider>(base3d);
651− provider->modelProviderType = NestableType::Overlay;
652− } else {
653− qCWarning(interfaceapp) << "no renderer for overlay ID" << overlayID.toString();
654− }
655− } else {
656− qCWarning(interfaceapp) << "overlay not found" << overlayID.toString();
657− }
658− return provider;
659− }
660−
661650 scriptable::ModelProviderPointer getAvatarModelProvider(QUuid sessionUUID) {
662651 scriptable::ModelProviderPointer provider;
663652 auto avatarManager = DependencyManager::get<AvatarManager>();
@@ -762,6 +751,11 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 98 unmodified lines
762751 static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
763752 bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
764753
754+ // set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store
755+ static const auto OCULUS_STORE_ARG = "--oculus-store";
756+ bool isStore = cmdOptionExists(argc, const_cast<const char**>(argv), OCULUS_STORE_ARG);
757+ qApp->setProperty(hifi::properties::OCULUS_STORE, isStore);
758+
765759 // Ignore any previous crashes if running from command line with a test script.
766760 bool inTestMode { false };
767761 for (int i = 0; i < argc; ++i) {
@@ -803,6 +797,9 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 35 unmodified lines
803797 if (auto steamClient = pluginManager->getSteamClientPlugin()) {
804798 steamClient->init();
805799 }
800+ if (auto oculusPlatform = pluginManager->getOculusPlatformPlugin()) {
801+ oculusPlatform->init();
802+ }
806803
807804 PROFILE_SET_THREAD_NAME("Main Thread");
808805
@@ -923,6 +920,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 114 unmodified lines
923920 DependencyManager::set<Wallet>();
924921 DependencyManager::set<WalletScriptingInterface>();
925922 DependencyManager::set<TTSScriptingInterface>();
923+ DependencyManager::set<QmlCommerce>();
926924
927925 DependencyManager::set<FadeEffect>();
928926 DependencyManager::set<ResourceRequestObserver>();
@@ -937,9 +935,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 8 unmodified lines
937935 // FIXME move to header, or better yet, design some kind of UI manager
938936 // to take care of highlighting keyboard focused items, rather than
939937 // continuing to overburden Application.cpp
940−std::shared_ptr<Cube3DOverlay> _keyboardFocusHighlight{ nullptr };
941−OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID };
942−
938+QUuid _keyboardFocusHighlightID;
943939
944940 OffscreenGLCanvas* _qmlShareContext { nullptr };
945941
@@ -980,7 +976,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 34 unmodified lines
980976 QApplication(argc, argv),
981977 _window(new MainWindow(desktop())),
982978 _sessionRunTimer(startupTimer),
979+#ifndef Q_OS_ANDROID
983980 _logger(new FileLogger(this)),
981+#endif
984982 _previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)),
985983 _entitySimulation(new PhysicalEntitySimulation()),
986984 _physicsEngine(new PhysicsEngine(Vectors::ZERO)),
@@ -1114,7 +1112,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 127 unmodified lines
11141112 }
11151113 auto accountManager = DependencyManager::get<AccountManager>();
11161114
1115+#ifndef Q_OS_ANDROID
11171116 _logger->setSessionID(accountManager->getSessionID());
1117+#endif
11181118
11191119 setCrashAnnotation("metaverse_session_id", accountManager->getSessionID().toString().toStdString());
11201120 setCrashAnnotation("main_thread_id", std::to_string((size_t)QThread::currentThreadId()));
@@ -1135,10 +1135,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 14 unmodified lines
11351135 qCDebug(interfaceapp) << "[VERSION] We will use DEVELOPMENT global services.";
11361136 #endif
11371137
1138− // set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store
1139− static const QString OCULUS_STORE_ARG = "--oculus-store";
1140− bool isStore = arguments().indexOf(OCULUS_STORE_ARG) != -1;
1141− setProperty(hifi::properties::OCULUS_STORE, isStore);
1138+ bool isStore = property(hifi::properties::OCULUS_STORE).toBool();
1139+
11421140 DependencyManager::get<WalletScriptingInterface>()->setLimitedCommerce(isStore); // Or we could make it a separate arg, or if either arg is set, etc. And should this instead by a hifi::properties?
11431141
11441142 updateHeartbeat();
@@ -1204,9 +1202,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 59 unmodified lines
12041202 connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle()));
12051203 connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
12061204 connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() {
1207− getOverlays().deleteOverlay(getTabletScreenID());
1208− getOverlays().deleteOverlay(getTabletHomeButtonID());
1209− getOverlays().deleteOverlay(getTabletFrameID());
1205+ auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
1206+ if (tabletScriptingInterface) {
1207+ tabletScriptingInterface->setQmlTabletRoot(SYSTEM_TABLET, nullptr);
1208+ }
1209+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
1210+ entityScriptingInterface->deleteEntity(getTabletScreenID());
1211+ entityScriptingInterface->deleteEntity(getTabletHomeButtonID());
1212+ entityScriptingInterface->deleteEntity(getTabletFrameID());
12101213 _failedToConnectToEntityServer = false;
12111214 });
12121215
@@ -1296,10 +1299,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 83 unmodified lines
12961299 if (isHMDMode()) {
12971300 emit loginDialogFocusDisabled();
12981301 dialogsManager->hideLoginDialog();
1299− createLoginDialogOverlay();
1302+ createLoginDialog();
13001303 } else {
1301− getOverlays().deleteOverlay(_loginDialogOverlayID);
1302− _loginDialogOverlayID = OverlayID();
1304+ DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_loginDialogID);
1305+ _loginDialogID = QUuid();
13031306 _loginStateManager.tearDown();
13041307 dialogsManager->showLoginDialog();
13051308 emit loginDialogFocusEnabled();
@@ -1896,66 +1899,56 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 590 unmodified lines
18961899 SpacemouseManager::getInstance().init();
18971900 #endif
18981901
1899− // 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
1900− auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
1901− connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity,
1902− [this](const EntityItemID& entityItemID, const PointerEvent& event) {
1902+ // If the user clicks on an object, we will check that it's a web surface, and if so, set the focus to it
1903+ auto pointerManager = DependencyManager::get<PointerManager>();
1904+ auto keyboardFocusOperator = [this](const QUuid& id, const PointerEvent& event) {
19031905 if (event.shouldFocus()) {
1904− if (getEntities()->wantsKeyboardFocus(entityItemID)) {
1905− setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
1906− setKeyboardFocusEntity(entityItemID);
1907− } else {
1906+ auto keyboard = DependencyManager::get<Keyboard>();
1907+ if (getEntities()->wantsKeyboardFocus(id)) {
1908+ setKeyboardFocusEntity(id);
1909+ } else if (!keyboard->containsID(id)) { // FIXME: this is a hack to make the keyboard work for now, since the keys would otherwise steal focus
19081910 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
19091911 }
19101912 }
1911− });
1913+ };
1914+ connect(pointerManager.data(), &PointerManager::triggerBeginEntity, keyboardFocusOperator);
1915+ connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, keyboardFocusOperator);
19121916
1913− connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [this](const EntityItemID& entityItemID) {
1917+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
1918+ connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityItemID) {
19141919 if (entityItemID == _keyboardFocusedEntity.get()) {
19151920 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
19161921 }
1917− });
1922+ }, Qt::QueuedConnection);
19181923
1919− EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
1924+ EntityTreeRenderer::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
19201925 if (_aboutToQuit) {
19211926 return false;
19221927 }
19231928
1924− // try to find the renderable
19251929 auto renderable = getEntities()->renderableForEntityId(entityID);
19261930 if (renderable) {
19271931 renderable->addMaterial(material, parentMaterialName);
1928− }
1929−
1930− // even if we don't find it, try to find the entity
1931− auto entity = getEntities()->getEntity(entityID);
1932− if (entity) {
1933− entity->addMaterial(material, parentMaterialName);
19341932 return true;
19351933 }
1934+
19361935 return false;
19371936 });
1938− EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
1937+ EntityTreeRenderer::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
19391938 if (_aboutToQuit) {
19401939 return false;
19411940 }
19421941
1943− // try to find the renderable
19441942 auto renderable = getEntities()->renderableForEntityId(entityID);
19451943 if (renderable) {
19461944 renderable->removeMaterial(material, parentMaterialName);
1947− }
1948−
1949− // even if we don't find it, try to find the entity
1950− auto entity = getEntities()->getEntity(entityID);
1951− if (entity) {
1952− entity->removeMaterial(material, parentMaterialName);
19531945 return true;
19541946 }
1947+
19551948 return false;
19561949 });
19571950
1958− EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
1951+ EntityTreeRenderer::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
19591952 auto avatarManager = DependencyManager::get<AvatarManager>();
19601953 auto avatar = avatarManager->getAvatarBySessionID(avatarID);
19611954 if (avatar) {
@@ -1964,7 +1957,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 2 unmodified lines
19641957 }
19651958 return false;
19661959 });
1967− EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
1960+ EntityTreeRenderer::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
19681961 auto avatarManager = DependencyManager::get<AvatarManager>();
19691962 auto avatar = avatarManager->getAvatarBySessionID(avatarID);
19701963 if (avatar) {
@@ -1974,33 +1967,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 3 unmodified lines
19741967 return false;
19751968 });
19761969
1977− EntityTree::setAddMaterialToOverlayOperator([this](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
1978− auto overlay = _overlays.getOverlay(overlayID);
1979− if (overlay) {
1980− overlay->addMaterial(material, parentMaterialName);
1981− return true;
1982− }
1983− return false;
1984− });
1985− EntityTree::setRemoveMaterialFromOverlayOperator([this](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
1986− auto overlay = _overlays.getOverlay(overlayID);
1987− if (overlay) {
1988− overlay->removeMaterial(material, parentMaterialName);
1989− return true;
1970+ EntityTree::setGetEntityObjectOperator([this](const QUuid& id) -> QObject* {
1971+ auto entities = getEntities();
1972+ if (auto entity = entities->renderableForEntityId(id)) {
1973+ return qobject_cast<QObject*>(entity.get());
19901974 }
1991− return false;
1975+ return nullptr;
19921976 });
19931977
1994− // Keyboard focus handling for Web overlays.
1995− auto overlays = &(qApp->getOverlays());
1996− connect(overlays, &Overlays::overlayDeleted, [this](const OverlayID& overlayID) {
1997− if (overlayID == _keyboardFocusedOverlay.get()) {
1998− setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
1978+ EntityTree::setTextSizeOperator([this](const QUuid& id, const QString& text) {
1979+ auto entities = getEntities();
1980+ if (auto entity = entities->renderableForEntityId(id)) {
1981+ if (auto renderable = std::dynamic_pointer_cast<render::entities::TextEntityRenderer>(entity)) {
1982+ return renderable->textSize(text);
1983+ }
19991984 }
1985+ return QSizeF(0.0f, 0.0f);
20001986 });
20011987
20021988 connect(this, &Application::aboutToQuit, [this]() {
2003− setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
20041989 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
20051990 });
20061991
@@ -2211,7 +2196,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 204 unmodified lines
22112196 || ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose));
22122197 lastLeftHandPose = leftHandPose;
22132198 lastRightHandPose = rightHandPose;
2214− properties["avatar_identity_requests_sent"] = DependencyManager::get<AvatarManager>()->getIdentityRequestsSent();
22152199
22162200 UserActivityLogger::getInstance().logAction("stats", properties);
22172201 });
@@ -2296,7 +2280,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 78 unmodified lines
22962280
22972281 // Setup the mouse ray pick and related operators
22982282 {
2299− auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES()), 0.0f, true);
2283+ auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_LOCAL_ENTITIES()), 0.0f, true);
23002284 mouseRayPick->parentTransform = std::make_shared<MouseTransformNode>();
23012285 mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE);
23022286 auto mouseRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, mouseRayPick);
@@ -2322,11 +2306,104 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 19 unmodified lines
23222306 DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
23232307 });
23242308
2325− EntityTreeRenderer::setGetAvatarUpOperator([] {
2326− return DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
2309+ EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) {
2310+ if (billboardMode == BillboardMode::YAW) {
2311+ //rotate about vertical to face the camera
2312+ ViewFrustum frustum;
2313+ copyViewFrustum(frustum);
2314+ glm::vec3 dPosition = frustum.getPosition() - position;
2315+ // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
2316+ float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
2317+ return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
2318+ } else if (billboardMode == BillboardMode::FULL) {
2319+ ViewFrustum frustum;
2320+ copyViewFrustum(frustum);
2321+ glm::vec3 cameraPos = frustum.getPosition();
2322+ // use the referencial from the avatar, y isn't always up
2323+ glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
2324+ // check to see if glm::lookAt will work / using glm::lookAt variable name
2325+ glm::highp_vec3 s(glm::cross(position - cameraPos, avatarUP));
2326+
2327+ // make sure s is not NaN for any component
2328+ if (glm::length2(s) > 0.0f) {
2329+ return glm::conjugate(glm::toQuat(glm::lookAt(cameraPos, position, avatarUP)));
2330+ }
2331+ }
2332+ return rotation;
2333+ });
2334+
2335+ render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
2336+ bool isTablet = url == TabletScriptingInterface::QML;
2337+ if (htmlContent) {
2338+ webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(render::entities::WebEntityRenderer::QML);
2339+ cachedWebSurface = true;
2340+ auto rootItemLoadedFunctor = [url, webSurface] {
2341+ webSurface->getRootItem()->setProperty(render::entities::WebEntityRenderer::URL_PROPERTY, url);
2342+ };
2343+ if (webSurface->getRootItem()) {
2344+ rootItemLoadedFunctor();
2345+ } else {
2346+ QObject::connect(webSurface.data(), &hifi::qml::OffscreenSurface::rootContextCreated, rootItemLoadedFunctor);
2347+ }
2348+ } else {
2349+ // FIXME: the tablet should use the OffscreenQmlSurfaceCache
2350+ webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), [](OffscreenQmlSurface* webSurface) {
2351+ AbstractViewStateInterface::instance()->sendLambdaEvent([webSurface] {
2352+ // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
2353+ // if the application has already stopped its event loop, delete must be explicit
2354+ delete webSurface;
2355+ });
2356+ });
2357+ auto rootItemLoadedFunctor = [webSurface, url, isTablet] {
2358+ Application::setupQmlSurface(webSurface->getSurfaceContext(), isTablet || url == LOGIN_DIALOG.toString());
2359+ };
2360+ if (webSurface->getRootItem()) {
2361+ rootItemLoadedFunctor();
2362+ } else {
2363+ QObject::connect(webSurface.data(), &hifi::qml::OffscreenSurface::rootContextCreated, rootItemLoadedFunctor);
2364+ }
2365+ webSurface->load(url);
2366+ cachedWebSurface = false;
2367+ }
2368+ const uint8_t DEFAULT_MAX_FPS = 10;
2369+ const uint8_t TABLET_FPS = 90;
2370+ webSurface->setMaxFps(isTablet ? TABLET_FPS : DEFAULT_MAX_FPS);
2371+ });
2372+ render::entities::WebEntityRenderer::setReleaseWebSurfaceOperator([this](QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface, std::vector<QMetaObject::Connection>& connections) {
2373+ QQuickItem* rootItem = webSurface->getRootItem();
2374+
2375+ // Fix for crash in QtWebEngineCore when rapidly switching domains
2376+ // Call stop on the QWebEngineView before destroying OffscreenQMLSurface.
2377+ if (rootItem && !cachedWebSurface) {
2378+ // stop loading
2379+ QMetaObject::invokeMethod(rootItem, "stop");
2380+ }
2381+
2382+ webSurface->pause();
2383+
2384+ for (auto& connection : connections) {
2385+ QObject::disconnect(connection);
2386+ }
2387+ connections.clear();
2388+
2389+ // If the web surface was fetched out of the cache, release it back into the cache
2390+ if (cachedWebSurface) {
2391+ // If it's going back into the cache make sure to explicitly set the URL to a blank page
2392+ // in order to stop any resource consumption or audio related to the page.
2393+ if (rootItem) {
2394+ rootItem->setProperty("url", "about:blank");
2395+ }
2396+ auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
2397+ if (offscreenCache) {
2398+ offscreenCache->release(render::entities::WebEntityRenderer::QML, webSurface);
2399+ }
2400+ cachedWebSurface = false;
2401+ }
2402+ webSurface.reset();
23272403 });
23282404
23292405 // Preload Tablet sounds
2406+ DependencyManager::get<EntityScriptingInterface>()->setEntityTree(qApp->getEntities()->getTree());
23302407 DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
23312408 DependencyManager::get<Keyboard>()->createKeyboard();
23322409
@@ -2352,7 +2429,6 @@ void Application::updateVerboseLogging() { · 19 unmodified lines
23522429 bool enable = menu->isOptionChecked(MenuOption::VerboseLogging);
23532430
23542431 QString rules =
2355− "hifi.*.debug=%1\n"
23562432 "hifi.*.info=%1\n"
23572433 "hifi.audio-stream.debug=false\n"
23582434 "hifi.audio-stream.info=false";
@@ -2535,11 +2611,10 @@ void Application::cleanupBeforeQuit() { · 176 unmodified lines
25352611 _applicationStateDevice.reset();
25362612
25372613 {
2538− if (_keyboardFocusHighlightID != UNKNOWN_OVERLAY_ID) {
2539− getOverlays().deleteOverlay(_keyboardFocusHighlightID);
2540− _keyboardFocusHighlightID = UNKNOWN_OVERLAY_ID;
2614+ if (_keyboardFocusHighlightID != UNKNOWN_ENTITY_ID) {
2615+ DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_keyboardFocusHighlightID);
2616+ _keyboardFocusHighlightID = UNKNOWN_ENTITY_ID;
25412617 }
2542− _keyboardFocusHighlight = nullptr;
25432618 }
25442619
25452620 {
@@ -2609,6 +2684,7 @@ void Application::cleanupBeforeQuit() { · 63 unmodified lines
26092684 DependencyManager::destroy<ContextOverlayInterface>(); // Must be destroyed before TabletScriptingInterface
26102685
26112686 // stop QML
2687+ DependencyManager::destroy<QmlCommerce>();
26122688 DependencyManager::destroy<TabletScriptingInterface>();
26132689 DependencyManager::destroy<ToolbarScriptingInterface>();
26142690 DependencyManager::destroy<OffscreenUi>();
@@ -2648,7 +2724,14 @@ Application::~Application() { · 33 unmodified lines
26482724 avatarManager->handleProcessedPhysicsTransaction(transaction);
26492725
26502726 avatarManager->deleteAllAvatars();
2651−
2727+
2728+ auto myCharacterController = getMyAvatar()->getCharacterController();
2729+ myCharacterController->clearDetailedMotionStates();
2730+
2731+ myCharacterController->buildPhysicsTransaction(transaction);
2732+ _physicsEngine->processTransaction(transaction);
2733+ myCharacterController->handleProcessedPhysicsTransaction(transaction);
2734+
26522735 _physicsEngine->setCharacterController(nullptr);
26532736
26542737 // the _shapeManager should have zero references
@@ -2671,6 +2754,11 @@ Application::~Application() { · 16 unmodified lines
26712754 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
26722755 steamClient->shutdown();
26732756 }
2757+
2758+ if (auto oculusPlatform = PluginManager::getInstance()->getOculusPlatformPlugin()) {
2759+ oculusPlatform->shutdown();
2760+ }
2761+
26742762 DependencyManager::destroy<PluginManager>();
26752763
26762764 DependencyManager::destroy<CompositorHelper>(); // must be destroyed before the FramebufferCache
@@ -2897,7 +2985,7 @@ void Application::initializeUi() { · 220 unmodified lines
28972985 Tooltip::registerType();
28982986 UpdateDialog::registerType();
28992987 QmlContextCallback commerceCallback = [](QQmlContext* context) {
2900− context->setContextProperty("Commerce", new QmlCommerce());
2988+ context->setContextProperty("Commerce", DependencyManager::get<QmlCommerce>().data());
29012989 };
29022990 OffscreenQmlSurface::addWhitelistContextHandler({
29032991 QUrl{ "hifi/commerce/checkout/Checkout.qml" },
@@ -2922,7 +3010,24 @@ void Application::initializeUi() { · 18 unmodified lines
29223010 QUrl{ "hifi/dialogs/security/SecurityImageChange.qml" },
29233011 QUrl{ "hifi/dialogs/security/SecurityImageModel.qml" },
29243012 QUrl{ "hifi/dialogs/security/SecurityImageSelection.qml" },
3013+ QUrl{ "hifi/tablet/TabletMenu.qml" },
3014+ QUrl{ "hifi/commerce/marketplace/Marketplace.qml" },
29253015 }, commerceCallback);
3016+
3017+ QmlContextCallback marketplaceCallback = [](QQmlContext* context) {
3018+ context->setContextProperty("MarketplaceScriptingInterface", new QmlMarketplace());
3019+ };
3020+ OffscreenQmlSurface::addWhitelistContextHandler({
3021+ QUrl{ "hifi/commerce/marketplace/Marketplace.qml" },
3022+ }, marketplaceCallback);
3023+
3024+ QmlContextCallback platformInfoCallback = [](QQmlContext* context) {
3025+ context->setContextProperty("PlatformInfo", new PlatformInfoScriptingInterface());
3026+ };
3027+ OffscreenQmlSurface::addWhitelistContextHandler({
3028+ QUrl{ "hifi/commerce/marketplace/Marketplace.qml" },
3029+ }, platformInfoCallback);
3030+
29263031 QmlContextCallback ttsCallback = [](QQmlContext* context) {
29273032 context->setContextProperty("TextToSpeech", DependencyManager::get<TTSScriptingInterface>().data());
29283033 };
@@ -3013,7 +3118,7 @@ void Application::initializeUi() { · 84 unmodified lines
30133118 });
30143119
30153120 #if !defined(DISABLE_QML)
3016− // Pre-create a couple of Web3D overlays to speed up tablet UI
3121+ // Pre-create a couple of offscreen surfaces to speed up tablet UI
30173122 auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
30183123 offscreenSurfaceCache->setOnRootContextCreated([&](const QString& rootObject, QQmlContext* surfaceContext) {
30193124 if (rootObject == TabletScriptingInterface::QML) {
@@ -3025,7 +3130,7 @@ void Application::initializeUi() { · 5 unmodified lines
30253130 });
30263131
30273132 offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1);
3028− offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
3133+ offscreenSurfaceCache->reserve(render::entities::WebEntityRenderer::QML, 2);
30293134 #endif
30303135
30313136 flushMenuUpdates();
@@ -3165,6 +3270,61 @@ void Application::onDesktopRootItemCreated(QQuickItem* rootItem) { · 133 unmodified lines
31653270 #endif
31663271 }
31673272
3273+void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditionalContextProperties) {
3274+ surfaceContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
3275+ surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
3276+ surfaceContext->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
3277+ surfaceContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
3278+ surfaceContext->setContextProperty("Vec3", new Vec3());
3279+ surfaceContext->setContextProperty("Quat", new Quat());
3280+ surfaceContext->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
3281+ surfaceContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
3282+ surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
3283+
3284+ if (setAdditionalContextProperties) {
3285+ auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
3286+ auto flags = tabletScriptingInterface->getFlags();
3287+
3288+ surfaceContext->setContextProperty("offscreenFlags", flags);
3289+ surfaceContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
3290+
3291+ surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
3292+ surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
3293+ surfaceContext->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
3294+
3295+ surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
3296+ surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
3297+ surfaceContext->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
3298+
3299+ // in Qt 5.10.0 there is already an "Audio" object in the QML context
3300+ // though I failed to find it (from QtMultimedia??). So.. let it be "AudioScriptingInterface"
3301+ surfaceContext->setContextProperty("AudioScriptingInterface", DependencyManager::get<AudioScriptingInterface>().data());
3302+
3303+ surfaceContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
3304+ surfaceContext->setContextProperty("fileDialogHelper", new FileDialogHelper());
3305+ surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
3306+ surfaceContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
3307+ surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
3308+ surfaceContext->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
3309+ surfaceContext->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
3310+ surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
3311+ surfaceContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
3312+ surfaceContext->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
3313+ surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
3314+ surfaceContext->setContextProperty("SoundCache", DependencyManager::get<SoundCacheScriptingInterface>().data());
3315+ surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
3316+ surfaceContext->setContextProperty("Render", AbstractViewStateInterface::instance()->getRenderEngine()->getConfiguration().get());
3317+ surfaceContext->setContextProperty("Workload", qApp->getGameWorkload()._engine->getConfiguration().get());
3318+ surfaceContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
3319+ surfaceContext->setContextProperty("Pointers", DependencyManager::get<PointerScriptingInterface>().data());
3320+ surfaceContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
3321+ surfaceContext->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
3322+ surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance());
3323+ surfaceContext->setContextProperty("WalletScriptingInterface", DependencyManager::get<WalletScriptingInterface>().data());
3324+ surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
3325+ }
3326+}
3327+
31683328 void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
31693329 PROFILE_RANGE(render, __FUNCTION__);
31703330 PerformanceTimer perfTimer("updateCamera");
@@ -3421,8 +3581,10 @@ void Application::resizeGL() { · 250 unmodified lines
34213581 auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
34223582 assert(renderConfig);
34233583 auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask");
3424− assert(mainView);
3425− mainView->setProperty("resolutionScale", renderResolutionScale);
3584+ // mainView can be null if we're rendering in forward mode
3585+ if (mainView) {
3586+ mainView->setProperty("resolutionScale", renderResolutionScale);
3587+ }
34263588 displayPlugin->setRenderResolutionScale(renderResolutionScale);
34273589 }
34283590
@@ -3677,8 +3839,8 @@ static inline bool isKeyEvent(QEvent::Type type) { · 248 unmodified lines
36773839 return type == QEvent::KeyPress || type == QEvent::KeyRelease;
36783840 }
36793841
3680−bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) {
3681− if (!_keyboardFocusedEntity.get().isInvalidID()) {
3842+bool Application::handleKeyEventForFocusedEntity(QEvent* event) {
3843+ if (_keyboardFocusedEntity.get() != UNKNOWN_ENTITY_ID) {
36823844 switch (event->type()) {
36833845 case QEvent::KeyPress:
36843846 case QEvent::KeyRelease:
@@ -3699,28 +3861,6 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { · 14 unmodified lines
36993861 }
37003862 }
37013863
3702− if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) {
3703− switch (event->type()) {
3704− case QEvent::KeyPress:
3705− case QEvent::KeyRelease: {
3706− // Only Web overlays can have focus.
3707− auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get()));
3708− if (overlay && overlay->getEventHandler()) {
3709− event->setAccepted(false);
3710− QCoreApplication::sendEvent(overlay->getEventHandler(), event);
3711− if (event->isAccepted()) {
3712− _lastAcceptedKeyPress = usecTimestampNow();
3713− return true;
3714− }
3715− }
3716− }
3717− break;
3718−
3719− default:
3720− break;
3721− }
3722− }
3723−
37243864 return false;
37253865 }
37263866
@@ -3763,8 +3903,8 @@ bool Application::event(QEvent* event) { · 36 unmodified lines
37633903 return false;
37643904 }
37653905
3766− // Allow focused Entities and Overlays to handle keyboard input
3767− if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event)) {
3906+ // Allow focused Entities to handle keyboard input
3907+ if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntity(event)) {
37683908 return true;
37693909 }
37703910
@@ -3970,6 +4110,19 @@ void Application::keyPressEvent(QKeyEvent* event) { · 199 unmodified lines
39704110 }
39714111 break;
39724112
4113+ case Qt::Key_G:
4114+ if (isShifted && isMeta && Menu::getInstance() && Menu::getInstance()->getMenu("Developer")->isVisible()) {
4115+ static const QString HIFI_FRAMES_FOLDER_VAR = "HIFI_FRAMES_FOLDER";
4116+ static const QString GPU_FRAME_FOLDER = QProcessEnvironment::systemEnvironment().contains(HIFI_FRAMES_FOLDER_VAR)
4117+ ? QProcessEnvironment::systemEnvironment().value(HIFI_FRAMES_FOLDER_VAR)
4118+ : "hifiFrames";
4119+ static QString GPU_FRAME_TEMPLATE = GPU_FRAME_FOLDER + "/{DATE}_{TIME}";
4120+ QString fullPath = FileUtils::computeDocumentPath(FileUtils::replaceDateTimeTokens(GPU_FRAME_TEMPLATE));
4121+ if (FileUtils::canCreateFile(fullPath)) {
4122+ getActiveDisplayPlugin()->captureFrame(fullPath.toStdString());
4123+ }
4124+ }
4125+ break;
39734126 case Qt::Key_X:
39744127 if (isShifted && isMeta) {
39754128 auto offscreenUi = getOffscreenUI();
@@ -4041,7 +4194,9 @@ void Application::keyPressEvent(QKeyEvent* event) { · 65 unmodified lines
40414194 if (!isShifted && !isMeta && !isOption && !event->isAutoRepeat()) {
40424195 AudioInjectorOptions options;
40434196 options.localOnly = true;
4197+ options.positionSet = false; // system sound
40444198 options.stereo = true;
4199+
40454200 Setting::Handle<bool> notificationSounds{ MenuOption::NotificationSounds, true };
40464201 Setting::Handle<bool> notificationSoundSnapshot{ MenuOption::NotificationSoundsSnapshot, true };
40474202 if (notificationSounds.get() && notificationSoundSnapshot.get()) {
@@ -4230,9 +4385,9 @@ void Application::mouseMoveEvent(QMouseEvent* event) { · 182 unmodified lines
42304385 buttons, event->modifiers());
42314386
42324387 if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
4233− getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) {
4234− getOverlays().mouseMoveEvent(&mappedEvent);
4388+ getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_ENTITY_ID) {
42354389 getEntities()->mouseMoveEvent(&mappedEvent);
4390+ getOverlays().mouseMoveEvent(&mappedEvent);
42364391 }
42374392
42384393 _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
@@ -4264,15 +4419,16 @@ void Application::mousePressEvent(QMouseEvent* event) { · 25 unmodified lines
42644419 #else
42654420 QPointF transformedPos;
42664421 #endif
4267− QMouseEvent mappedEvent(event->type(),
4268− transformedPos,
4269− event->screenPos(), event->button(),
4270− event->buttons(), event->modifiers());
42714422
4272− getOverlays().mousePressEvent(&mappedEvent);
4423+ QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers());
4424+ std::pair<float, QUuid> entityResult;
42734425 if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
4274− getEntities()->mousePressEvent(&mappedEvent);
4426+ entityResult = getEntities()->mousePressEvent(&mappedEvent);
42754427 }
4428+ std::pair<float, QUuid> overlayResult = getOverlays().mousePressEvent(&mappedEvent);
4429+
4430+ QUuid focusedEntity = entityResult.first < overlayResult.first ? entityResult.second : overlayResult.second;
4431+ setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(focusedEntity) ? focusedEntity : UNKNOWN_ENTITY_ID);
42764432
42774433 _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
42784434
@@ -4312,10 +4468,10 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { · 33 unmodified lines
43124468 event->screenPos(), event->button(),
43134469 event->buttons(), event->modifiers());
43144470
4315− getOverlays().mouseDoublePressEvent(&mappedEvent);
43164471 if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
43174472 getEntities()->mouseDoublePressEvent(&mappedEvent);
43184473 }
4474+ getOverlays().mouseDoublePressEvent(&mappedEvent);
43194475
43204476 // if one of our scripts have asked to capture this event, then stop processing it
43214477 if (_controllerScriptingInterface->isMouseCaptured()) {
@@ -4339,8 +4495,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { · 17 unmodified lines
43394495 event->screenPos(), event->button(),
43404496 event->buttons(), event->modifiers());
43414497
4342− getOverlays().mouseReleaseEvent(&mappedEvent);
43434498 getEntities()->mouseReleaseEvent(&mappedEvent);
4499+ getOverlays().mouseReleaseEvent(&mappedEvent);
43444500
43454501 _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
43464502
@@ -4751,6 +4907,10 @@ void Application::idle() { · 404 unmodified lines
47514907 steamClient->runCallbacks();
47524908 }
47534909
4910+ if (auto oculusPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
4911+ oculusPlugin->handleOVREvents();
4912+ }
4913+
47544914 float secondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_MSEC / MSECS_PER_SECOND;
47554915 _lastTimeUpdated.start();
47564916
@@ -4784,7 +4944,11 @@ void Application::idle() { · 27 unmodified lines
47844944 // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
47854945 // details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing
47864946 // details normally.
4947+#ifdef Q_OS_ANDROID
4948+ bool showWarnings = false;
4949+#else
47874950 bool showWarnings = getLogger()->extraDebugging();
4951+#endif
47884952 PerformanceWarning warn(showWarnings, "idle()");
47894953
47904954 {
@@ -4798,31 +4962,19 @@ void Application::idle() { · 7 unmodified lines
47984962 update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS));
47994963 }
48004964
4801−
4802− // Update focus highlight for entity or overlay.
4803− {
4804− if (!_keyboardFocusedEntity.get().isInvalidID() || _keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) {
4965+ { // Update keyboard focus highlight
4966+ if (!_keyboardFocusedEntity.get().isInvalidID()) {
48054967 const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
48064968 quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;
48074969 if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {
48084970 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
4809− setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
48104971 } else {
4811− // update position of highlight overlay
4812− if (!_keyboardFocusedEntity.get().isInvalidID()) {
4813− auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
4814− if (entity && _keyboardFocusHighlight) {
4815− _keyboardFocusHighlight->setWorldOrientation(entity->getWorldOrientation());
4816− _keyboardFocusHighlight->setWorldPosition(entity->getWorldPosition());
4817− }
4818− } else {
4819− // Only Web overlays can have focus.
4820− auto overlay =
4821− std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get()));
4822− if (overlay && _keyboardFocusHighlight) {
4823− _keyboardFocusHighlight->setWorldOrientation(overlay->getWorldOrientation());
4824− _keyboardFocusHighlight->setWorldPosition(overlay->getWorldPosition());
4825− }
4972+ if (auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get())) {
4973+ EntityItemProperties properties;
4974+ properties.setPosition(entity->getWorldPosition());
4975+ properties.setRotation(entity->getWorldOrientation());
4976+ properties.setDimensions(entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
4977+ DependencyManager::get<EntityScriptingInterface>()->editEntity(_keyboardFocusHighlightID, properties);
48264978 }
48274979 }
48284980 }
@@ -5620,118 +5772,80 @@ void Application::rotationModeChanged() const { · 791 unmodified lines
56205772 }
56215773
56225774 void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions) {
5623− // Create focus
56245775 if (qApp->getLoginDialogPoppedUp()) {
56255776 return;
56265777 }
5627− if (_keyboardFocusHighlightID == UNKNOWN_OVERLAY_ID || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
5628− _keyboardFocusHighlight = std::make_shared<Cube3DOverlay>();
5629− _keyboardFocusHighlight->setAlpha(1.0f);
5630− _keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });
5631− _keyboardFocusHighlight->setIsSolid(false);
5632− _keyboardFocusHighlight->setPulseMin(0.5);
5633− _keyboardFocusHighlight->setPulseMax(1.0);
5634− _keyboardFocusHighlight->setColorPulse(1.0);
5635− _keyboardFocusHighlight->setIgnorePickIntersection(true);
5636− _keyboardFocusHighlight->setDrawInFront(false);
5637− _keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);
5778+
5779+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
5780+ if (_keyboardFocusHighlightID == UNKNOWN_ENTITY_ID || !entityScriptingInterface->isAddedEntity(_keyboardFocusHighlightID)) {
5781+ EntityItemProperties properties;
5782+ properties.setType(EntityTypes::Box);
5783+ properties.setAlpha(1.0f);
5784+ properties.setColor({ 0xFF, 0xEF, 0x00 });
5785+ properties.setPrimitiveMode(PrimitiveMode::LINES);
5786+ properties.getPulse().setMin(0.5);
5787+ properties.getPulse().setMax(1.0f);
5788+ properties.getPulse().setColorMode(PulseMode::IN_PHASE);
5789+ properties.setIgnorePickIntersection(true);
5790+ _keyboardFocusHighlightID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
56385791 }
56395792
56405793 // Position focus
5641− _keyboardFocusHighlight->setWorldOrientation(rotation);
5642− _keyboardFocusHighlight->setWorldPosition(position);
5643− _keyboardFocusHighlight->setDimensions(dimensions);
5644− _keyboardFocusHighlight->setVisible(true);
5794+ EntityItemProperties properties;
5795+ properties.setPosition(position);
5796+ properties.setRotation(rotation);
5797+ properties.setDimensions(dimensions);
5798+ properties.setVisible(true);
5799+ entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
56455800 }
56465801
56475802 QUuid Application::getKeyboardFocusEntity() const {
56485803 return _keyboardFocusedEntity.get();
56495804 }
56505805
5651−static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
5652−
5653−void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
5654− if (qApp->getLoginDialogPoppedUp()) {
5655− return;
5656− }
5657− if (_keyboardFocusedEntity.get() != entityItemID) {
5658− _keyboardFocusedEntity.set(entityItemID);
5659−
5660− if (_keyboardFocusHighlight && _keyboardFocusedOverlay.get() == UNKNOWN_OVERLAY_ID) {
5661− _keyboardFocusHighlight->setVisible(false);
5662− }
5663−
5664− if (entityItemID == UNKNOWN_ENTITY_ID) {
5665− return;
5666− }
5667−
5668− auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
5669− auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
5670− if (!properties.getLocked() && properties.getVisible()) {
5671−
5672− auto entities = getEntities();
5673− auto entityId = _keyboardFocusedEntity.get();
5674− if (entities->wantsKeyboardFocus(entityId)) {
5675− entities->setProxyWindow(entityId, _window->windowHandle());
5676− if (_keyboardMouseDevice->isActive()) {
5677− _keyboardMouseDevice->pluginFocusOutEvent();
5678− }
5679− _lastAcceptedKeyPress = usecTimestampNow();
5680−
5681− auto entity = getEntities()->getEntity(entityId);
5682− if (entity) {
5683− setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
5684− entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
5685− }
5686− }
5687− }
5688− }
5689−}
5690−
5691−OverlayID Application::getKeyboardFocusOverlay() {
5692− return _keyboardFocusedOverlay.get();
5693−}
5694−
5695−void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) {
5696− if (overlayID != _keyboardFocusedOverlay.get()) {
5697− if (qApp->getLoginDialogPoppedUp() && !_loginDialogOverlayID.isNull()) {
5698− if (overlayID == _loginDialogOverlayID) {
5806+void Application::setKeyboardFocusEntity(const QUuid& id) {
5807+ if (_keyboardFocusedEntity.get() != id) {
5808+ if (qApp->getLoginDialogPoppedUp() && !_loginDialogID.isNull()) {
5809+ if (id == _loginDialogID) {
56995810 emit loginDialogFocusEnabled();
57005811 } else {
5701− // that's the only overlay we want in focus;
5812+ // that's the only entity we want in focus;
57025813 return;
57035814 }
57045815 }
57055816
5706− _keyboardFocusedOverlay.set(overlayID);
5707−
5708− if (_keyboardFocusHighlight && _keyboardFocusedEntity.get() == UNKNOWN_ENTITY_ID) {
5709− _keyboardFocusHighlight->setVisible(false);
5710− }
5711−
5712− if (overlayID == UNKNOWN_OVERLAY_ID) {
5713− return;
5714− }
5817+ _keyboardFocusedEntity.set(id);
57155818
5716− auto overlayType = getOverlays().getOverlayType(overlayID);
5717− auto isVisible = getOverlays().getProperty(overlayID, "visible").value.toBool();
5718− if (overlayType == Web3DOverlay::TYPE && isVisible) {
5719− auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(overlayID));
5720− overlay->setProxyWindow(_window->windowHandle());
5819+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
5820+ if (id != UNKNOWN_ENTITY_ID) {
5821+ EntityPropertyFlags desiredProperties;
5822+ desiredProperties += PROP_VISIBLE;
5823+ desiredProperties += PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT;
5824+ auto properties = entityScriptingInterface->getEntityProperties(id);
5825+ if (properties.getVisible()) {
5826+ auto entities = getEntities();
5827+ auto entityId = _keyboardFocusedEntity.get();
5828+ if (entities->wantsKeyboardFocus(entityId)) {
5829+ entities->setProxyWindow(entityId, _window->windowHandle());
5830+ if (_keyboardMouseDevice->isActive()) {
5831+ _keyboardMouseDevice->pluginFocusOutEvent();
5832+ }
5833+ _lastAcceptedKeyPress = usecTimestampNow();
57215834
5722− if (_keyboardMouseDevice->isActive()) {
5723− _keyboardMouseDevice->pluginFocusOutEvent();
5724− }
5725− _lastAcceptedKeyPress = usecTimestampNow();
5726−
5727− if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) {
5728− auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR;
5729− const float OVERLAY_DEPTH = 0.0105f;
5730− setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH));
5731− } else if (_keyboardFocusHighlight) {
5732− _keyboardFocusHighlight->setVisible(false);
5835+ if (properties.getShowKeyboardFocusHighlight()) {
5836+ if (auto entity = entities->getEntity(entityId)) {
5837+ setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
5838+ entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
5839+ return;
5840+ }
5841+ }
5842+ }
57335843 }
57345844 }
5845+
5846+ EntityItemProperties properties;
5847+ properties.setVisible(false);
5848+ entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
57355849 }
57365850 }
57375851
@@ -5935,6 +6049,13 @@ void Application::update(float deltaTime) { · 197 unmodified lines
59356049
59366050 auto userInputMapper = DependencyManager::get<UserInputMapper>();
59376051
6052+ controller::HmdAvatarAlignmentType hmdAvatarAlignmentType;
6053+ if (myAvatar->getHmdAvatarAlignmentType() == "eyes") {
6054+ hmdAvatarAlignmentType = controller::HmdAvatarAlignmentType::Eyes;
6055+ } else {
6056+ hmdAvatarAlignmentType = controller::HmdAvatarAlignmentType::Head;
6057+ }
6058+
59386059 controller::InputCalibrationData calibrationData = {
59396060 myAvatar->getSensorToWorldMatrix(),
59406061 createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()),
@@ -5948,7 +6069,8 @@ void Application::update(float deltaTime) { · 7 unmodified lines
59486069 myAvatar->getRightArmCalibrationMat(),
59496070 myAvatar->getLeftArmCalibrationMat(),
59506071 myAvatar->getRightHandCalibrationMat(),
5951− myAvatar->getLeftHandCalibrationMat()
6072+ myAvatar->getLeftHandCalibrationMat(),
6073+ hmdAvatarAlignmentType
59526074 };
59536075
59546076 InputPluginPointer keyboardMousePlugin;
@@ -6100,6 +6222,19 @@ void Application::update(float deltaTime) { · 145 unmodified lines
61006222 auto grabManager = DependencyManager::get<GrabManager>();
61016223 grabManager->simulateGrabs();
61026224
6225+ // TODO: break these out into distinct perfTimers when they prove interesting
6226+ {
6227+ PROFILE_RANGE(app, "PickManager");
6228+ PerformanceTimer perfTimer("pickManager");
6229+ DependencyManager::get<PickManager>()->update();
6230+ }
6231+
6232+ {
6233+ PROFILE_RANGE(app, "PointerManager");
6234+ PerformanceTimer perfTimer("pointerManager");
6235+ DependencyManager::get<PointerManager>()->update();
6236+ }
6237+
61036238 QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
61046239
61056240 {
@@ -6113,36 +6248,57 @@ void Application::update(float deltaTime) { · 7 unmodified lines
61136248 PROFILE_RANGE(simulation_physics, "PrePhysics");
61146249 PerformanceTimer perfTimer("prePhysics)");
61156250 {
6251+ PROFILE_RANGE(simulation_physics, "RemoveEntities");
61166252 const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics();
6117− _physicsEngine->removeObjects(motionStates);
6253+ {
6254+ PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
6255+ _physicsEngine->removeObjects(motionStates);
6256+ }
61186257 _entitySimulation->deleteObjectsRemovedFromPhysics();
61196258 }
61206259
6121− VectorOfMotionStates motionStates;
6122− getEntities()->getTree()->withReadLock([&] {
6123− _entitySimulation->getObjectsToAddToPhysics(motionStates);
6124− _physicsEngine->addObjects(motionStates);
6125−
6126− });
6127− getEntities()->getTree()->withReadLock([&] {
6128− _entitySimulation->getObjectsToChange(motionStates);
6129− VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
6130− _entitySimulation->setObjectsToChange(stillNeedChange);
6131− });
6260+ {
6261+ PROFILE_RANGE(simulation_physics, "AddEntities");
6262+ VectorOfMotionStates motionStates;
6263+ getEntities()->getTree()->withReadLock([&] {
6264+ _entitySimulation->getObjectsToAddToPhysics(motionStates);
6265+ PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
6266+ _physicsEngine->addObjects(motionStates);
6267+ });
6268+ }
6269+ {
6270+ VectorOfMotionStates motionStates;
6271+ PROFILE_RANGE(simulation_physics, "ChangeEntities");
6272+ getEntities()->getTree()->withReadLock([&] {
6273+ _entitySimulation->getObjectsToChange(motionStates);
6274+ VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
6275+ _entitySimulation->setObjectsToChange(stillNeedChange);
6276+ });
6277+ }
61326278
61336279 _entitySimulation->applyDynamicChanges();
61346280
61356281 t1 = std::chrono::high_resolution_clock::now();
61366282
6137− PhysicsEngine::Transaction transaction;
6138− avatarManager->buildPhysicsTransaction(transaction);
6139− _physicsEngine->processTransaction(transaction);
6140− avatarManager->handleProcessedPhysicsTransaction(transaction);
6283+ {
6284+ PROFILE_RANGE(simulation_physics, "Avatars");
6285+ PhysicsEngine::Transaction transaction;
6286+ avatarManager->buildPhysicsTransaction(transaction);
6287+ _physicsEngine->processTransaction(transaction);
6288+ avatarManager->handleProcessedPhysicsTransaction(transaction);
6289+ myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
6290+ _physicsEngine->processTransaction(transaction);
6291+ myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction);
6292+ myAvatar->prepareForPhysicsSimulation();
6293+ _physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying());
6294+ }
61416295
6142− myAvatar->prepareForPhysicsSimulation();
6143− _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
6144− dynamic->prepareForPhysicsSimulation();
6145− });
6296+ {
6297+ PROFILE_RANGE(simulation_physics, "PrepareActions");
6298+ _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
6299+ dynamic->prepareForPhysicsSimulation();
6300+ });
6301+ }
61466302 }
61476303 auto t2 = std::chrono::high_resolution_clock::now();
61486304 {
@@ -6245,22 +6401,9 @@ void Application::update(float deltaTime) { · 96 unmodified lines
62456401
62466402 updateLOD(deltaTime);
62476403
6248− if (!_loginDialogOverlayID.isNull()) {
6249− _loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogOverlayID);
6250− updateLoginDialogOverlayPosition();
6251− }
6252−
6253− // TODO: break these out into distinct perfTimers when they prove interesting
6254− {
6255− PROFILE_RANGE(app, "PickManager");
6256− PerformanceTimer perfTimer("pickManager");
6257− DependencyManager::get<PickManager>()->update();
6258− }
6259−
6260− {
6261− PROFILE_RANGE(app, "PointerManager");
6262− PerformanceTimer perfTimer("pointerManager");
6263− DependencyManager::get<PointerManager>()->update();
6404+ if (!_loginDialogID.isNull()) {
6405+ _loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogID);
6406+ updateLoginDialogPosition();
62646407 }
62656408
62666409 {
@@ -6284,7 +6427,7 @@ void Application::update(float deltaTime) { · 17 unmodified lines
62846427 // TODO: Fix this by modeling the way the secondary camera works on how the main camera works
62856428 // ie. Use a camera object stored in the game logic and informs the Engine on where the secondary
62866429 // camera should be.
6287− // updateSecondaryCameraViewFrustum();
6430+ updateSecondaryCameraViewFrustum();
62886431 }
62896432
62906433 quint64 now = usecTimestampNow();
@@ -6843,17 +6986,19 @@ void Application::nodeActivated(SharedNodePointer node) { · 552 unmodified lines
68436986
68446987 #if !defined(DISABLE_QML)
68456988 auto offscreenUi = getOffscreenUI();
6846− auto assetDialog = offscreenUi ? offscreenUi->getRootItem()->findChild<QQuickItem*>("AssetServer") : nullptr;
68476989
6848− if (assetDialog) {
6990+ if (offscreenUi) {
68496991 auto nodeList = DependencyManager::get<NodeList>();
68506992
68516993 if (nodeList->getThisNodeCanWriteAssets()) {
68526994 // call reload on the shown asset browser dialog to get the mappings (if permissions allow)
6853− QMetaObject::invokeMethod(assetDialog, "reload");
6995+ auto assetDialog = offscreenUi ? offscreenUi->getRootItem()->findChild<QQuickItem*>("AssetServer") : nullptr;
6996+ if (assetDialog) {
6997+ QMetaObject::invokeMethod(assetDialog, "reload");
6998+ }
68546999 } else {
68557000 // we switched to an Asset Server that we can't modify, hide the Asset Browser
6856− assetDialog->setVisible(false);
7001+ offscreenUi->hide("AssetServer");
68577002 }
68587003 }
68597004 #endif
@@ -7026,7 +7171,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe · 166 unmodified lines
70267171 connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
70277172
70287173 scriptEngine->registerGlobalObject("Overlays", &_overlays);
7029− qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
70307174 qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue,
70317175 RayToOverlayIntersectionResultFromScriptValue);
70327176
@@ -7143,8 +7287,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe · 110 unmodified lines
71437287 scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
71447288 scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
71457289
7146− qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
7147−
71487290 registerInteractiveWindowMetaType(scriptEngine.data());
71497291
71507292 auto pickScriptingInterface = DependencyManager::get<PickScriptingInterface>();
@@ -8025,8 +8167,7 @@ void Application::openUrl(const QUrl& url) const { · 874 unmodified lines
80258167 if (url.scheme() == URL_SCHEME_HIFI) {
80268168 DependencyManager::get<AddressManager>()->handleLookupString(url.toString());
80278169 } else if (url.scheme() == URL_SCHEME_HIFIAPP) {
8028− QmlCommerce commerce;
8029− commerce.openSystemApp(url.path());
8170+ DependencyManager::get<QmlCommerce>()->openSystemApp(url.path());
80308171 } else {
80318172 // address manager did not handle - ask QDesktopServices to handle
80328173 QDesktopServices::openUrl(url);
@@ -8112,7 +8253,18 @@ void Application::toggleLogDialog() { · 79 unmodified lines
81128253 return;
81138254 }
81148255 if (! _logDialog) {
8256+
8257+ bool keepOnTop =_keepLogWindowOnTop.get();
8258+#ifdef Q_OS_WIN
8259+ _logDialog = new LogDialog(keepOnTop ? qApp->getWindow() : nullptr, getLogger());
8260+#elif !defined(Q_OS_ANDROID)
81158261 _logDialog = new LogDialog(nullptr, getLogger());
8262+
8263+ if (keepOnTop) {
8264+ Qt::WindowFlags flags = _logDialog->windowFlags() | Qt::Tool;
8265+ _logDialog->setWindowFlags(flags);
8266+ }
8267+#endif
81168268 }
81178269
81188270 if (_logDialog->isVisible()) {
@@ -8122,6 +8274,19 @@ void Application::toggleLogDialog() { · 3 unmodified lines
81228274 }
81238275 }
81248276
8277+ void Application::recreateLogWindow(int keepOnTop) {
8278+ _keepLogWindowOnTop.set(keepOnTop != 0);
8279+ if (_logDialog) {
8280+ bool toggle = _logDialog->isVisible();
8281+ _logDialog->close();
8282+ _logDialog = nullptr;
8283+
8284+ if (toggle) {
8285+ toggleLogDialog();
8286+ }
8287+ }
8288+ }
8289+
81258290 void Application::toggleEntityScriptServerLogDialog() {
81268291 if (! _entityScriptServerLogDialog) {
81278292 _entityScriptServerLogDialog = new EntityScriptServerLogDialog(nullptr);
@@ -8643,45 +8808,47 @@ void Application::setShowBulletConstraintLimits(bool value) { · 515 unmodified lines
86438808 _physicsEngine->setShowBulletConstraintLimits(value);
86448809 }
86458810
8646−void Application::createLoginDialogOverlay() {
8647− const glm::vec2 LOGIN_OVERLAY_DIMENSIONS{ 0.89f, 0.5f };
8648− const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f);
8811+void Application::createLoginDialog() {
8812+ const glm::vec3 LOGIN_DIMENSIONS { 0.89f, 0.5f, 0.01f };
8813+ const auto OFFSET = glm::vec2(0.7f, -0.1f);
86498814 auto cameraPosition = _myCamera.getPosition();
86508815 auto cameraOrientation = _myCamera.getOrientation();
86518816 auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
86528817 auto headLookVec = (cameraOrientation * Vectors::FRONT);
86538818 // DEFAULT_DPI / tablet scale percentage
8654− const float OVERLAY_DPI = 31.0f / (75.0f / 100.0f);
8655− auto offset = headLookVec * OVERLAY_OFFSET.x;
8656− auto overlayPosition = (cameraPosition + offset) + (upVec * OVERLAY_OFFSET.y);
8657− QVariantMap overlayProperties = {
8658− { "name", "LoginDialogOverlay" },
8659− { "url", OVERLAY_LOGIN_DIALOG },
8660− { "position", vec3toVariant(overlayPosition) },
8661− { "orientation", quatToVariant(cameraOrientation) },
8662− { "isSolid", true },
8663− { "grabbable", false },
8664− { "ignorePickIntersection", false },
8665− { "alpha", 1.0 },
8666− { "dimensions", vec2ToVariant(LOGIN_OVERLAY_DIMENSIONS)},
8667− { "dpi", OVERLAY_DPI },
8668− { "visible", true }
8669− };
8670− auto& overlays = getOverlays();
8671− _loginDialogOverlayID = overlays.addOverlay("web3d", overlayProperties);
8672− auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID));
8819+ const float DPI = 31.0f / (75.0f / 100.0f);
8820+ auto offset = headLookVec * OFFSET.x;
8821+ auto position = (cameraPosition + offset) + (upVec * OFFSET.y);
8822+
8823+ EntityItemProperties properties;
8824+ properties.setType(EntityTypes::Web);
8825+ properties.setName("LoginDialogEntity");
8826+ properties.setSourceUrl(LOGIN_DIALOG.toString());
8827+ properties.setPosition(position);
8828+ properties.setRotation(cameraOrientation);
8829+ properties.setDimensions(LOGIN_DIMENSIONS);
8830+ properties.setPrimitiveMode(PrimitiveMode::SOLID);
8831+ properties.getGrab().setGrabbable(false);
8832+ properties.setIgnorePickIntersection(false);
8833+ properties.setAlpha(1.0f);
8834+ properties.setDPI(DPI);
8835+ properties.setVisible(true);
8836+
8837+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
8838+ _loginDialogID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
8839+
86738840 auto keyboard = DependencyManager::get<Keyboard>().data();
8674− if (!keyboard->getAnchorID().isNull() && !_loginDialogOverlayID.isNull()) {
8675− const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
8841+ if (!keyboard->getAnchorID().isNull() && !_loginDialogID.isNull()) {
86768842 auto keyboardLocalOffset = cameraOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
8677− QVariantMap properties {
8678− { "position", vec3toVariant(overlayPosition + keyboardLocalOffset) },
8679− { "orientation", quatToVariant(cameraOrientation * KEYBOARD_LOCAL_ORIENTATION) },
8680− };
8681− overlays.editOverlay(keyboard->getAnchorID(), properties);
8843+
8844+ EntityItemProperties properties;
8845+ properties.setPosition(position + keyboardLocalOffset);
8846+ properties.setRotation(cameraOrientation * Quaternions::Y_180);
8847+
8848+ entityScriptingInterface->editEntity(keyboard->getAnchorID(), properties);
86828849 keyboard->setResetKeyboardPositionOnRaise(false);
86838850 }
8684− setKeyboardFocusOverlay(_loginDialogOverlayID);
8851+ setKeyboardFocusEntity(_loginDialogID);
86858852 emit loginDialogFocusEnabled();
86868853 getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(false);
86878854 getApplicationCompositor().getReticleInterface()->setVisible(false);
@@ -8690,38 +8857,43 @@ void Application::createLoginDialogOverlay() { · 2 unmodified lines
86908857 }
86918858 }
86928859
8693−void Application::updateLoginDialogOverlayPosition() {
8860+void Application::updateLoginDialogPosition() {
86948861 const float LOOK_AWAY_THRESHOLD_ANGLE = 70.0f;
8695− const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f);
8696− auto& overlays = getOverlays();
8697− auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID));
8698− auto overlayPositionVec = loginOverlay->getWorldPosition();
8862+ const auto OFFSET = glm::vec2(0.7f, -0.1f);
8863+
8864+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
8865+ EntityPropertyFlags desiredProperties;
8866+ desiredProperties += PROP_POSITION;
8867+ auto properties = entityScriptingInterface->getEntityProperties(_loginDialogID, desiredProperties);
8868+ auto positionVec = properties.getPosition();
86998869 auto cameraPositionVec = _myCamera.getPosition();
87008870 auto cameraOrientation = cancelOutRollAndPitch(_myCamera.getOrientation());
87018871 auto headLookVec = (cameraOrientation * Vectors::FRONT);
8702− auto overlayToHeadVec = overlayPositionVec - cameraPositionVec;
8703− auto pointAngle = (glm::acos(glm::dot(glm::normalize(overlayToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
8872+ auto entityToHeadVec = positionVec - cameraPositionVec;
8873+ auto pointAngle = (glm::acos(glm::dot(glm::normalize(entityToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
87048874 auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
8705− auto offset = headLookVec * OVERLAY_OFFSET.x;
8706− auto newOverlayPositionVec = (cameraPositionVec + offset) + (upVec * OVERLAY_OFFSET.y);
8707− auto newOverlayOrientation = glm::inverse(glm::quat_cast(glm::lookAt(newOverlayPositionVec, cameraPositionVec, upVec))) * Quaternions::Y_180;
8875+ auto offset = headLookVec * OFFSET.x;
8876+ auto newPositionVec = (cameraPositionVec + offset) + (upVec * OFFSET.y);
87088877
8709− bool overlayOutOfBounds = glm::distance(overlayPositionVec, cameraPositionVec) > 1.0f;
8878+ bool outOfBounds = glm::distance(positionVec, cameraPositionVec) > 1.0f;
87108879
8711− if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || overlayOutOfBounds) {
8712− QVariantMap properties {
8713− {"position", vec3toVariant(newOverlayPositionVec)},
8714− {"orientation", quatToVariant(newOverlayOrientation)}
8715− };
8716− overlays.editOverlay(_loginDialogOverlayID, properties);
8717− const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
8718− auto keyboardLocalOffset = newOverlayOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
8719− QVariantMap keyboardProperties {
8720− { "position", vec3toVariant(newOverlayPositionVec + keyboardLocalOffset) },
8721− { "orientation", quatToVariant(newOverlayOrientation * KEYBOARD_LOCAL_ORIENTATION) },
8722− };
8723− auto keyboard = DependencyManager::get<Keyboard>().data();
8724− overlays.editOverlay(keyboard->getAnchorID(), keyboardProperties);
8880+ if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || outOfBounds) {
8881+ {
8882+ EntityItemProperties properties;
8883+ properties.setPosition(newPositionVec);
8884+ properties.setRotation(cameraOrientation);
8885+ entityScriptingInterface->editEntity(_loginDialogID, properties);
8886+ }
8887+
8888+ {
8889+ glm::vec3 keyboardLocalOffset = cameraOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
8890+ glm::quat keyboardOrientation = cameraOrientation * glm::quat(glm::radians(glm::vec3(-30.0f, 180.0f, 0.0f)));
8891+
8892+ EntityItemProperties properties;
8893+ properties.setPosition(newPositionVec + keyboardLocalOffset);
8894+ properties.setRotation(keyboardOrientation);
8895+ entityScriptingInterface->editEntity(DependencyManager::get<Keyboard>()->getAnchorID(), properties);
8896+ }
87258897 }
87268898 }
87278899
@@ -8738,10 +8910,9 @@ void Application::onDismissedLoginDialog() { · 10 unmodified lines
87388910 loginDialogPoppedUp.set(false);
87398911 auto keyboard = DependencyManager::get<Keyboard>().data();
87408912 keyboard->setResetKeyboardPositionOnRaise(true);
8741− if (!_loginDialogOverlayID.isNull()) {
8742− // deleting overlay.
8743− getOverlays().deleteOverlay(_loginDialogOverlayID);
8744− _loginDialogOverlayID = OverlayID();
8913+ if (!_loginDialogID.isNull()) {
8914+ DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_loginDialogID);
8915+ _loginDialogID = QUuid();
87458916 _loginStateManager.tearDown();
87468917 }
87478918 resumeAfterLoginDialogActionTaken();
@@ -8907,12 +9078,12 @@ void Application::updateSystemTabletMode() { · 159 unmodified lines
89079078 }
89089079 }
89099080
8910−OverlayID Application::getTabletScreenID() const {
9081+QUuid Application::getTabletScreenID() const {
89119082 auto HMD = DependencyManager::get<HMDScriptingInterface>();
89129083 return HMD->getCurrentTabletScreenID();
89139084 }
89149085
8915−OverlayID Application::getTabletHomeButtonID() const {
9086+QUuid Application::getTabletHomeButtonID() const {
89169087 auto HMD = DependencyManager::get<HMDScriptingInterface>();
89179088 return HMD->getCurrentHomeButtonID();
89189089 }
@@ -8923,7 +9094,7 @@ QUuid Application::getTabletFrameID() const { · 4 unmodified lines
89239094 }
89249095
89259096 QVector<QUuid> Application::getTabletIDs() const {
8926− // Most important overlays first.
9097+ // Most important first.
89279098 QVector<QUuid> result;
89289099 auto HMD = DependencyManager::get<HMDScriptingInterface>();
89299100 result << HMD->getCurrentTabletScreenID();