remove overlays from application.cpp

This commit is contained in:
SamGondelman 2019-01-24 14:11:24 -08:00
parent a75fe4b48b
commit 0bfcde67ea
13 changed files with 587 additions and 546 deletions

View file

@ -151,6 +151,7 @@
#include <trackers/EyeTracker.h> #include <trackers/EyeTracker.h>
#include <avatars-renderer/ScriptAvatar.h> #include <avatars-renderer/ScriptAvatar.h>
#include <RenderableEntityItem.h> #include <RenderableEntityItem.h>
#include <RenderableTextEntityItem.h>
#include <RenderableWebEntityItem.h> #include <RenderableWebEntityItem.h>
#include <model-networking/MaterialCache.h> #include <model-networking/MaterialCache.h>
#include "recording/ClipCache.h" #include "recording/ClipCache.h"
@ -196,8 +197,6 @@
#include "ui/AvatarInputs.h" #include "ui/AvatarInputs.h"
#include "ui/DialogsManager.h" #include "ui/DialogsManager.h"
#include "ui/LoginDialog.h" #include "ui/LoginDialog.h"
#include "ui/overlays/Cube3DOverlay.h"
#include "ui/overlays/Web3DOverlay.h"
#include "ui/Snapshot.h" #include "ui/Snapshot.h"
#include "ui/SnapshotAnimated.h" #include "ui/SnapshotAnimated.h"
#include "ui/StandAloneJSConsole.h" #include "ui/StandAloneJSConsole.h"
@ -618,8 +617,6 @@ public:
switch (type) { switch (type) {
case NestableType::Entity: case NestableType::Entity:
return getEntityModelProvider(static_cast<EntityItemID>(uuid)); return getEntityModelProvider(static_cast<EntityItemID>(uuid));
case NestableType::Overlay:
return getOverlayModelProvider(static_cast<OverlayID>(uuid));
case NestableType::Avatar: case NestableType::Avatar:
return getAvatarModelProvider(uuid); return getAvatarModelProvider(uuid);
} }
@ -643,22 +640,6 @@ private:
return provider; 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 getAvatarModelProvider(QUuid sessionUUID) {
scriptable::ModelProviderPointer provider; scriptable::ModelProviderPointer provider;
auto avatarManager = DependencyManager::get<AvatarManager>(); auto avatarManager = DependencyManager::get<AvatarManager>();
@ -935,9 +916,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
// FIXME move to header, or better yet, design some kind of UI manager // FIXME move to header, or better yet, design some kind of UI manager
// to take care of highlighting keyboard focused items, rather than // to take care of highlighting keyboard focused items, rather than
// continuing to overburden Application.cpp // continuing to overburden Application.cpp
std::shared_ptr<Cube3DOverlay> _keyboardFocusHighlight{ nullptr }; QUuid _keyboardFocusHighlightID;
OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID };
OffscreenGLCanvas* _qmlShareContext { nullptr }; OffscreenGLCanvas* _qmlShareContext { nullptr };
@ -1206,9 +1185,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (tabletScriptingInterface) { if (tabletScriptingInterface) {
tabletScriptingInterface->setQmlTabletRoot(SYSTEM_TABLET, nullptr); tabletScriptingInterface->setQmlTabletRoot(SYSTEM_TABLET, nullptr);
} }
getOverlays().deleteOverlay(getTabletScreenID()); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
getOverlays().deleteOverlay(getTabletHomeButtonID()); entityScriptingInterface->deleteEntity(getTabletScreenID());
getOverlays().deleteOverlay(getTabletFrameID()); entityScriptingInterface->deleteEntity(getTabletHomeButtonID());
entityScriptingInterface->deleteEntity(getTabletFrameID());
_failedToConnectToEntityServer = false; _failedToConnectToEntityServer = false;
}); });
@ -1298,10 +1278,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (isHMDMode()) { if (isHMDMode()) {
emit loginDialogFocusDisabled(); emit loginDialogFocusDisabled();
dialogsManager->hideLoginDialog(); dialogsManager->hideLoginDialog();
createLoginDialogOverlay(); createLoginDialog();
} else { } else {
getOverlays().deleteOverlay(_loginDialogOverlayID); DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_loginDialogID);
_loginDialogOverlayID = OverlayID(); _loginDialogID = QUuid();
_loginStateManager.tearDown(); _loginStateManager.tearDown();
dialogsManager->showLoginDialog(); dialogsManager->showLoginDialog();
emit loginDialogFocusEnabled(); emit loginDialogFocusEnabled();
@ -1898,7 +1878,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
[this](const EntityItemID& entityItemID, const PointerEvent& event) { [this](const EntityItemID& entityItemID, const PointerEvent& event) {
if (event.shouldFocus()) { if (event.shouldFocus()) {
if (getEntities()->wantsKeyboardFocus(entityItemID)) { if (getEntities()->wantsKeyboardFocus(entityItemID)) {
setKeyboardFocusLocalEntity(UNKNOWN_OVERLAY_ID); setKeyboardFocusLocalEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusEntity(entityItemID); setKeyboardFocusEntity(entityItemID);
} else { } else {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
@ -1970,33 +1950,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return false; return false;
}); });
EntityTree::setAddMaterialToOverlayOperator([this](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { EntityTree::setTextSizeOperator([this](const QUuid& id, const QString& text) {
auto overlay = _overlays.getOverlay(overlayID); auto entities = getEntities();
if (overlay) { if (auto entity = entities->renderableForEntityId(id)) {
overlay->addMaterial(material, parentMaterialName); if (auto renderable = std::dynamic_pointer_cast<render::entities::TextEntityRenderer>(entity)) {
return true; return renderable->textSize(text);
}
} }
return false; return QSizeF(0.0f, 0.0f);
});
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;
}); });
// Keyboard focus handling for Web overlays. // Keyboard focus handling for local Web entities.
auto overlays = &(qApp->getOverlays()); connect(&qApp->getOverlays(), &Overlays::overlayDeleted, [this](const QUuid& id) {
connect(overlays, &Overlays::overlayDeleted, [this](const OverlayID& overlayID) { if (id == _keyboardFocusedLocalEntity.get()) {
if (overlayID == _keyboardFocusedLocalEntity.get()) { setKeyboardFocusLocalEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusLocalEntity(UNKNOWN_OVERLAY_ID);
} }
}); });
connect(this, &Application::aboutToQuit, [this]() { connect(this, &Application::aboutToQuit, [this]() {
setKeyboardFocusLocalEntity(UNKNOWN_OVERLAY_ID); setKeyboardFocusLocalEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
}); });
@ -2344,7 +2316,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}); });
}); });
auto rootItemLoadedFunctor = [webSurface, url, isTablet] { 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()) { if (webSurface->getRootItem()) {
rootItemLoadedFunctor(); rootItemLoadedFunctor();
@ -2600,11 +2572,10 @@ void Application::cleanupBeforeQuit() {
_applicationStateDevice.reset(); _applicationStateDevice.reset();
{ {
if (_keyboardFocusHighlightID != UNKNOWN_OVERLAY_ID) { if (_keyboardFocusHighlightID != UNKNOWN_ENTITY_ID) {
getOverlays().deleteOverlay(_keyboardFocusHighlightID); DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_keyboardFocusHighlightID);
_keyboardFocusHighlightID = UNKNOWN_OVERLAY_ID; _keyboardFocusHighlightID = UNKNOWN_ENTITY_ID;
} }
_keyboardFocusHighlight = nullptr;
} }
{ {
@ -3080,7 +3051,7 @@ void Application::initializeUi() {
}); });
#if !defined(DISABLE_QML) #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>(); auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
offscreenSurfaceCache->setOnRootContextCreated([&](const QString& rootObject, QQmlContext* surfaceContext) { offscreenSurfaceCache->setOnRootContextCreated([&](const QString& rootObject, QQmlContext* surfaceContext) {
if (rootObject == TabletScriptingInterface::QML) { if (rootObject == TabletScriptingInterface::QML) {
@ -3799,7 +3770,7 @@ static inline bool isKeyEvent(QEvent::Type type) {
return type == QEvent::KeyPress || type == QEvent::KeyRelease; return type == QEvent::KeyPress || type == QEvent::KeyRelease;
} }
bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { bool Application::handleKeyEventForFocusedEntity(QEvent* event) {
if (!_keyboardFocusedEntity.get().isInvalidID()) { if (!_keyboardFocusedEntity.get().isInvalidID()) {
switch (event->type()) { switch (event->type()) {
case QEvent::KeyPress: case QEvent::KeyPress:
@ -3821,15 +3792,14 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) {
} }
} }
if (_keyboardFocusedLocalEntity.get() != UNKNOWN_OVERLAY_ID) { if (!_keyboardFocusedLocalEntity.get().isInvalidID()) {
switch (event->type()) { switch (event->type()) {
case QEvent::KeyPress: case QEvent::KeyPress:
case QEvent::KeyRelease: { case QEvent::KeyRelease: {
// Only Web entities can have focus. auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get());
auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedLocalEntity.get())); if (eventHandler) {
if (overlay && overlay->getEventHandler()) {
event->setAccepted(false); event->setAccepted(false);
QCoreApplication::sendEvent(overlay->getEventHandler(), event); QCoreApplication::sendEvent(eventHandler, event);
if (event->isAccepted()) { if (event->isAccepted()) {
_lastAcceptedKeyPress = usecTimestampNow(); _lastAcceptedKeyPress = usecTimestampNow();
return true; return true;
@ -3885,8 +3855,8 @@ bool Application::event(QEvent* event) {
return false; return false;
} }
// Allow focused Entities and Overlays to handle keyboard input // Allow focused Entities to handle keyboard input
if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event)) { if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntity(event)) {
return true; return true;
} }
@ -4352,7 +4322,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
buttons, event->modifiers()); buttons, event->modifiers());
if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() || if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) { !getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())).isNull()) {
getOverlays().mouseMoveEvent(&mappedEvent); getOverlays().mouseMoveEvent(&mappedEvent);
getEntities()->mouseMoveEvent(&mappedEvent); getEntities()->mouseMoveEvent(&mappedEvent);
} }
@ -4921,29 +4891,31 @@ void Application::idle() {
} }
// Update focus highlight for entity or overlay. // Update focus highlight for entities
{ {
if (!_keyboardFocusedEntity.get().isInvalidID() || _keyboardFocusedLocalEntity.get() != UNKNOWN_OVERLAY_ID) { if (!_keyboardFocusedEntity.get().isInvalidID() || !_keyboardFocusedLocalEntity.get().isInvalidID()) {
const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;
if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusLocalEntity(UNKNOWN_OVERLAY_ID); setKeyboardFocusLocalEntity(UNKNOWN_ENTITY_ID);
} else { } else {
// update position of highlight overlay // update position of highlight overlay
if (!_keyboardFocusedEntity.get().isInvalidID()) { if (!_keyboardFocusedEntity.get().isInvalidID()) {
auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get()); auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
if (entity && _keyboardFocusHighlight) { if (entity && !_keyboardFocusHighlightID.isNull()) {
_keyboardFocusHighlight->setWorldOrientation(entity->getWorldOrientation()); EntityItemProperties properties;
_keyboardFocusHighlight->setWorldPosition(entity->getWorldPosition()); properties.setPosition(entity->getWorldPosition());
properties.setRotation(entity->getWorldOrientation());
DependencyManager::get<EntityScriptingInterface>()->editEntity(_keyboardFocusHighlightID, properties);
} }
} else { } else {
// Only Web overlays can have focus. auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
auto overlay = if (entity && !_keyboardFocusHighlightID.isNull()) {
std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedLocalEntity.get())); EntityItemProperties properties;
if (overlay && _keyboardFocusHighlight) { properties.setPosition(entity->getWorldPosition());
_keyboardFocusHighlight->setWorldOrientation(overlay->getWorldOrientation()); properties.setRotation(entity->getWorldOrientation());
_keyboardFocusHighlight->setWorldPosition(overlay->getWorldPosition()); DependencyManager::get<EntityScriptingInterface>()->editEntity(_keyboardFocusHighlightID, properties);
} }
} }
} }
@ -5746,24 +5718,28 @@ void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm
if (qApp->getLoginDialogPoppedUp()) { if (qApp->getLoginDialogPoppedUp()) {
return; return;
} }
if (_keyboardFocusHighlightID == UNKNOWN_OVERLAY_ID || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight = std::make_shared<Cube3DOverlay>(); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
_keyboardFocusHighlight->setAlpha(1.0f); if (_keyboardFocusHighlightID == UNKNOWN_ENTITY_ID || !entityScriptingInterface->isAddedEntity(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 }); EntityItemProperties properties;
_keyboardFocusHighlight->setIsSolid(false); properties.setType(EntityTypes::Box);
_keyboardFocusHighlight->setPulseMin(0.5); properties.setAlpha(1.0f);
_keyboardFocusHighlight->setPulseMax(1.0); properties.setColor({ 0xFF, 0xEF, 0x00 });
_keyboardFocusHighlight->setColorPulse(1.0); properties.setPrimitiveMode(PrimitiveMode::LINES);
_keyboardFocusHighlight->setIgnorePickIntersection(true); properties.getPulse().setMin(0.5);
_keyboardFocusHighlight->setDrawInFront(false); properties.getPulse().setMax(1.0f);
_keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight); properties.getPulse().setColorMode(PulseMode::IN_PHASE);
properties.setIgnorePickIntersection(true);
_keyboardFocusHighlightID = entityScriptingInterface->addEntity(properties, "local");
} }
// Position focus // Position focus
_keyboardFocusHighlight->setWorldOrientation(rotation); EntityItemProperties properties;
_keyboardFocusHighlight->setWorldPosition(position); properties.setPosition(position);
_keyboardFocusHighlight->setDimensions(dimensions); properties.setRotation(rotation);
_keyboardFocusHighlight->setVisible(true); properties.setDimensions(dimensions);
properties.setVisible(true);
entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
} }
QUuid Application::getKeyboardFocusEntity() const { QUuid Application::getKeyboardFocusEntity() const {
@ -5779,18 +5755,16 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
if (_keyboardFocusedEntity.get() != entityItemID) { if (_keyboardFocusedEntity.get() != entityItemID) {
_keyboardFocusedEntity.set(entityItemID); _keyboardFocusedEntity.set(entityItemID);
if (_keyboardFocusHighlight && _keyboardFocusedLocalEntity.get() == UNKNOWN_OVERLAY_ID) { auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
_keyboardFocusHighlight->setVisible(false);
}
if (entityItemID == UNKNOWN_ENTITY_ID) { if (entityItemID == UNKNOWN_ENTITY_ID) {
EntityItemProperties properties;
properties.setVisible(false);
entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
return; return;
} }
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto properties = entityScriptingInterface->getEntityProperties(entityItemID); auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (!properties.getLocked() && properties.getVisible()) { if (!properties.getLocked() && properties.getVisible()) {
auto entities = getEntities(); auto entities = getEntities();
auto entityId = _keyboardFocusedEntity.get(); auto entityId = _keyboardFocusedEntity.get();
if (entities->wantsKeyboardFocus(entityId)) { if (entities->wantsKeyboardFocus(entityId)) {
@ -5814,44 +5788,43 @@ EntityItemID Application::getKeyboardFocusLocalEntity() {
return _keyboardFocusedLocalEntity.get(); return _keyboardFocusedLocalEntity.get();
} }
void Application::setKeyboardFocusLocalEntity(const EntityItemID& overlayID) { void Application::setKeyboardFocusLocalEntity(const EntityItemID& entityItemID) {
if (overlayID != _keyboardFocusedLocalEntity.get()) { if (entityItemID != _keyboardFocusedLocalEntity.get()) {
if (qApp->getLoginDialogPoppedUp() && !_loginDialogOverlayID.isNull()) { if (qApp->getLoginDialogPoppedUp() && !_loginDialogID.isNull()) {
if (overlayID == _loginDialogOverlayID) { if (entityItemID == _loginDialogID) {
emit loginDialogFocusEnabled(); emit loginDialogFocusEnabled();
} else { } else {
// that's the only overlay we want in focus; // that's the only entity we want in focus;
return; return;
} }
} }
_keyboardFocusedLocalEntity.set(overlayID); _keyboardFocusedLocalEntity.set(entityItemID);
if (_keyboardFocusHighlight && _keyboardFocusedEntity.get() == UNKNOWN_ENTITY_ID) { auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
_keyboardFocusHighlight->setVisible(false); if (entityItemID == UNKNOWN_ENTITY_ID) {
} EntityItemProperties properties;
properties.setVisible(false);
if (overlayID == UNKNOWN_OVERLAY_ID) { entityScriptingInterface->editEntity(_keyboardFocusHighlightID, properties);
return; return;
} }
auto overlayType = getOverlays().getOverlayType(overlayID); auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
auto isVisible = getOverlays().getProperty(overlayID, "visible").value.toBool(); if (!properties.getLocked() && properties.getVisible()) {
if (overlayType == Web3DOverlay::TYPE && isVisible) { auto entities = getEntities();
auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(overlayID)); auto entityId = _keyboardFocusedLocalEntity.get();
overlay->setProxyWindow(_window->windowHandle()); if (entities->wantsKeyboardFocus(entityId)) {
entities->setProxyWindow(entityId, _window->windowHandle());
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_lastAcceptedKeyPress = usecTimestampNow();
if (_keyboardMouseDevice->isActive()) { auto entity = getEntities()->getEntity(entityId);
_keyboardMouseDevice->pluginFocusOutEvent(); if (entity) {
} setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
_lastAcceptedKeyPress = usecTimestampNow(); entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
}
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);
} }
} }
} }
@ -6367,9 +6340,9 @@ void Application::update(float deltaTime) {
updateLOD(deltaTime); updateLOD(deltaTime);
if (!_loginDialogOverlayID.isNull()) { if (!_loginDialogID.isNull()) {
_loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogOverlayID); _loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogID);
updateLoginDialogOverlayPosition(); updateLoginDialogPosition();
} }
// TODO: break these out into distinct perfTimers when they prove interesting // TODO: break these out into distinct perfTimers when they prove interesting
@ -7148,7 +7121,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
scriptEngine->registerGlobalObject("Overlays", &_overlays); scriptEngine->registerGlobalObject("Overlays", &_overlays);
qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue,
RayToOverlayIntersectionResultFromScriptValue); RayToOverlayIntersectionResultFromScriptValue);
@ -7265,8 +7237,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data()); scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
registerInteractiveWindowMetaType(scriptEngine.data()); registerInteractiveWindowMetaType(scriptEngine.data());
auto pickScriptingInterface = DependencyManager::get<PickScriptingInterface>(); auto pickScriptingInterface = DependencyManager::get<PickScriptingInterface>();
@ -8764,45 +8734,48 @@ void Application::setShowBulletConstraintLimits(bool value) {
_physicsEngine->setShowBulletConstraintLimits(value); _physicsEngine->setShowBulletConstraintLimits(value);
} }
void Application::createLoginDialogOverlay() { void Application::createLoginDialog() {
const glm::vec2 LOGIN_OVERLAY_DIMENSIONS{ 0.89f, 0.5f }; const glm::vec3 LOGIN_DIMENSIONS { 0.89f, 0.5f, 0.01f };
const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f); const auto OFFSET = glm::vec2(0.7f, -0.1f);
auto cameraPosition = _myCamera.getPosition(); auto cameraPosition = _myCamera.getPosition();
auto cameraOrientation = _myCamera.getOrientation(); auto cameraOrientation = _myCamera.getOrientation();
auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y; auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
auto headLookVec = (cameraOrientation * Vectors::FRONT); auto headLookVec = (cameraOrientation * Vectors::FRONT);
// DEFAULT_DPI / tablet scale percentage // DEFAULT_DPI / tablet scale percentage
const float OVERLAY_DPI = 31.0f / (75.0f / 100.0f); const float DPI = 31.0f / (75.0f / 100.0f);
auto offset = headLookVec * OVERLAY_OFFSET.x; auto offset = headLookVec * OFFSET.x;
auto overlayPosition = (cameraPosition + offset) + (upVec * OVERLAY_OFFSET.y); auto position = (cameraPosition + offset) + (upVec * OFFSET.y);
QVariantMap overlayProperties = {
{ "name", "LoginDialogOverlay" }, EntityItemProperties properties;
{ "url", OVERLAY_LOGIN_DIALOG }, properties.setType(EntityTypes::Web);
{ "position", vec3toVariant(overlayPosition) }, properties.setName("LoginDialogEntity");
{ "orientation", quatToVariant(cameraOrientation) }, properties.setSourceUrl(LOGIN_DIALOG);
{ "isSolid", true }, properties.setPosition(position);
{ "grabbable", false }, properties.setRotation(cameraOrientation);
{ "ignorePickIntersection", false }, properties.setDimensions(LOGIN_DIMENSIONS);
{ "alpha", 1.0 }, properties.setPrimitiveMode(PrimitiveMode::SOLID);
{ "dimensions", vec2ToVariant(LOGIN_OVERLAY_DIMENSIONS)}, properties.getGrab().setGrabbable(false);
{ "dpi", OVERLAY_DPI }, properties.setIgnorePickIntersection(false);
{ "visible", true } properties.setAlpha(1.0f);
}; properties.setDPI(DPI);
auto& overlays = getOverlays(); properties.setVisible(true);
_loginDialogOverlayID = overlays.addOverlay("web3d", overlayProperties);
auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID)); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
_loginDialogID = entityScriptingInterface->addEntity(properties, "local");
auto keyboard = DependencyManager::get<Keyboard>().data(); auto keyboard = DependencyManager::get<Keyboard>().data();
if (!keyboard->getAnchorID().isNull() && !_loginDialogOverlayID.isNull()) { if (!keyboard->getAnchorID().isNull() && !_loginDialogID.isNull()) {
const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f); const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
auto keyboardLocalOffset = cameraOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f); auto keyboardLocalOffset = cameraOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
QVariantMap properties {
{ "position", vec3toVariant(overlayPosition + keyboardLocalOffset) }, EntityItemProperties properties;
{ "orientation", quatToVariant(cameraOrientation * KEYBOARD_LOCAL_ORIENTATION) }, properties.setPosition(position + keyboardLocalOffset);
}; properties.setRotation(cameraOrientation * KEYBOARD_LOCAL_ORIENTATION);
overlays.editOverlay(keyboard->getAnchorID(), properties);
entityScriptingInterface->editEntity(keyboard->getAnchorID(), properties);
keyboard->setResetKeyboardPositionOnRaise(false); keyboard->setResetKeyboardPositionOnRaise(false);
} }
setKeyboardFocusLocalEntity(_loginDialogOverlayID); setKeyboardFocusLocalEntity(_loginDialogID);
emit loginDialogFocusEnabled(); emit loginDialogFocusEnabled();
getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(false); getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(false);
getApplicationCompositor().getReticleInterface()->setVisible(false); getApplicationCompositor().getReticleInterface()->setVisible(false);
@ -8811,38 +8784,44 @@ void Application::createLoginDialogOverlay() {
} }
} }
void Application::updateLoginDialogOverlayPosition() { void Application::updateLoginDialogPosition() {
const float LOOK_AWAY_THRESHOLD_ANGLE = 70.0f; const float LOOK_AWAY_THRESHOLD_ANGLE = 70.0f;
const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f); const auto OFFSET = glm::vec2(0.7f, -0.1f);
auto& overlays = getOverlays();
auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID)); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto overlayPositionVec = loginOverlay->getWorldPosition(); EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
auto properties = entityScriptingInterface->getEntityProperties(_loginDialogID, desiredProperties);
auto positionVec = properties.getPosition();
auto cameraPositionVec = _myCamera.getPosition(); auto cameraPositionVec = _myCamera.getPosition();
auto cameraOrientation = cancelOutRollAndPitch(_myCamera.getOrientation()); auto cameraOrientation = cancelOutRollAndPitch(_myCamera.getOrientation());
auto headLookVec = (cameraOrientation * Vectors::FRONT); auto headLookVec = (cameraOrientation * Vectors::FRONT);
auto overlayToHeadVec = overlayPositionVec - cameraPositionVec; auto entityToHeadVec = positionVec - cameraPositionVec;
auto pointAngle = (glm::acos(glm::dot(glm::normalize(overlayToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI); auto pointAngle = (glm::acos(glm::dot(glm::normalize(entityToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y; auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
auto offset = headLookVec * OVERLAY_OFFSET.x; auto offset = headLookVec * OFFSET.x;
auto newOverlayPositionVec = (cameraPositionVec + offset) + (upVec * OVERLAY_OFFSET.y); auto newPositionVec = (cameraPositionVec + offset) + (upVec * OFFSET.y);
auto newOverlayOrientation = glm::inverse(glm::quat_cast(glm::lookAt(newOverlayPositionVec, cameraPositionVec, upVec))) * Quaternions::Y_180; auto newOrientation = glm::inverse(glm::quat_cast(glm::lookAt(newPositionVec, cameraPositionVec, upVec))) * Quaternions::Y_180;
bool overlayOutOfBounds = glm::distance(overlayPositionVec, cameraPositionVec) > 1.0f; bool outOfBounds = glm::distance(positionVec, cameraPositionVec) > 1.0f;
if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || overlayOutOfBounds) { if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || outOfBounds) {
QVariantMap properties { {
{"position", vec3toVariant(newOverlayPositionVec)}, EntityItemProperties properties;
{"orientation", quatToVariant(newOverlayOrientation)} properties.setPosition(newPositionVec);
}; properties.setRotation(newOrientation);
overlays.editOverlay(_loginDialogOverlayID, properties); entityScriptingInterface->editEntity(_loginDialogID, 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) }, const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
{ "orientation", quatToVariant(newOverlayOrientation * KEYBOARD_LOCAL_ORIENTATION) }, auto keyboardLocalOffset = newOrientation * glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
};
auto keyboard = DependencyManager::get<Keyboard>().data(); EntityItemProperties properties;
overlays.editOverlay(keyboard->getAnchorID(), keyboardProperties); properties.setPosition(newPositionVec + keyboardLocalOffset);
properties.setRotation(newOrientation * KEYBOARD_LOCAL_ORIENTATION);
entityScriptingInterface->editEntity(DependencyManager::get<Keyboard>()->getAnchorID(), properties);
}
} }
} }
@ -8859,10 +8838,9 @@ void Application::onDismissedLoginDialog() {
loginDialogPoppedUp.set(false); loginDialogPoppedUp.set(false);
auto keyboard = DependencyManager::get<Keyboard>().data(); auto keyboard = DependencyManager::get<Keyboard>().data();
keyboard->setResetKeyboardPositionOnRaise(true); keyboard->setResetKeyboardPositionOnRaise(true);
if (!_loginDialogOverlayID.isNull()) { if (!_loginDialogID.isNull()) {
// deleting overlay. DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_loginDialogID);
getOverlays().deleteOverlay(_loginDialogOverlayID); _loginDialogID = QUuid();
_loginDialogOverlayID = OverlayID();
_loginStateManager.tearDown(); _loginStateManager.tearDown();
} }
resumeAfterLoginDialogActionTaken(); resumeAfterLoginDialogActionTaken();
@ -9028,12 +9006,12 @@ void Application::updateSystemTabletMode() {
} }
} }
OverlayID Application::getTabletScreenID() const { QUuid Application::getTabletScreenID() const {
auto HMD = DependencyManager::get<HMDScriptingInterface>(); auto HMD = DependencyManager::get<HMDScriptingInterface>();
return HMD->getCurrentTabletScreenID(); return HMD->getCurrentTabletScreenID();
} }
OverlayID Application::getTabletHomeButtonID() const { QUuid Application::getTabletHomeButtonID() const {
auto HMD = DependencyManager::get<HMDScriptingInterface>(); auto HMD = DependencyManager::get<HMDScriptingInterface>();
return HMD->getCurrentHomeButtonID(); return HMD->getCurrentHomeButtonID();
} }
@ -9044,7 +9022,7 @@ QUuid Application::getTabletFrameID() const {
} }
QVector<QUuid> Application::getTabletIDs() const { QVector<QUuid> Application::getTabletIDs() const {
// Most important overlays first. // Most important first.
QVector<QUuid> result; QVector<QUuid> result;
auto HMD = DependencyManager::get<HMDScriptingInterface>(); auto HMD = DependencyManager::get<HMDScriptingInterface>();
result << HMD->getCurrentTabletScreenID(); result << HMD->getCurrentTabletScreenID();

View file

@ -297,10 +297,10 @@ public:
void shareSnapshot(const QString& filename, const QUrl& href = QUrl("")); void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));
OverlayID getTabletScreenID() const; QUuid getTabletScreenID() const;
OverlayID getTabletHomeButtonID() const; QUuid getTabletHomeButtonID() const;
QUuid getTabletFrameID() const; // may be an entity or an overlay QUuid getTabletFrameID() const;
QVector<QUuid> getTabletIDs() const; // In order of most important IDs first. QVector<QUuid> getTabletIDs() const;
void setAvatarOverrideUrl(const QUrl& url, bool save); void setAvatarOverrideUrl(const QUrl& url, bool save);
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; } void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
@ -323,8 +323,8 @@ public:
void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); } void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); }
bool getLoginDialogPoppedUp() const { return _loginDialogPoppedUp; } bool getLoginDialogPoppedUp() const { return _loginDialogPoppedUp; }
void createLoginDialogOverlay(); void createLoginDialog();
void updateLoginDialogOverlayPosition(); void updateLoginDialogPosition();
// Check if a headset is connected // Check if a headset is connected
bool hasRiftControllers(); bool hasRiftControllers();
@ -440,7 +440,7 @@ public slots:
void setKeyboardFocusEntity(const EntityItemID& entityItemID); void setKeyboardFocusEntity(const EntityItemID& entityItemID);
EntityItemID getKeyboardFocusLocalEntity(); EntityItemID getKeyboardFocusLocalEntity();
void setKeyboardFocusLocalEntity(const EntityItemID& overlayID); void setKeyboardFocusLocalEntity(const EntityItemID& id);
void addAssetToWorldMessageClose(); void addAssetToWorldMessageClose();
@ -531,7 +531,7 @@ private:
void init(); void init();
void pauseUntilLoginDetermined(); void pauseUntilLoginDetermined();
void resumeAfterLoginDialogActionTaken(); void resumeAfterLoginDialogActionTaken();
bool handleKeyEventForFocusedEntityOrOverlay(QEvent* event); bool handleKeyEventForFocusedEntity(QEvent* event);
bool handleFileOpenEvent(QFileOpenEvent* event); bool handleFileOpenEvent(QFileOpenEvent* event);
void cleanupBeforeQuit(); void cleanupBeforeQuit();
@ -702,7 +702,7 @@ private:
QString _previousAvatarSkeletonModel; QString _previousAvatarSkeletonModel;
float _previousAvatarTargetScale; float _previousAvatarTargetScale;
CameraMode _previousCameraMode; CameraMode _previousCameraMode;
OverlayID _loginDialogOverlayID; QUuid _loginDialogID;
LoginStateManager _loginStateManager; LoginStateManager _loginStateManager;
quint64 _lastFaceTrackerUpdate; quint64 _lastFaceTrackerUpdate;

View file

@ -33,7 +33,7 @@
HIFI_QML_DEF(LoginDialog) HIFI_QML_DEF(LoginDialog)
static const QUrl TABLET_LOGIN_DIALOG_URL("dialogs/TabletLoginDialog.qml"); 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) { LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
auto accountManager = DependencyManager::get<AccountManager>(); auto accountManager = DependencyManager::get<AccountManager>();
@ -70,7 +70,7 @@ void LoginDialog::showWithSelection() {
if (!qApp->getLoginDialogPoppedUp()) { if (!qApp->getLoginDialogPoppedUp()) {
tablet->initialScreen(TABLET_LOGIN_DIALOG_URL); tablet->initialScreen(TABLET_LOGIN_DIALOG_URL);
} else { } else {
qApp->createLoginDialogOverlay(); qApp->createLoginDialog();
} }
} }

View file

@ -54,18 +54,13 @@ Overlays::Overlays() {
void Overlays::cleanupAllOverlays() { void Overlays::cleanupAllOverlays() {
_shuttingDown = true; _shuttingDown = true;
QMap<OverlayID, Overlay::Pointer> overlaysHUD; QMap<QUuid, Overlay::Pointer> overlays;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
overlaysHUD.swap(_overlaysHUD); overlays.swap(_overlays);
overlaysWorld.swap(_overlaysWorld);
} }
foreach(Overlay::Pointer overlay, overlaysHUD) { foreach(Overlay::Pointer overlay, overlays) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, overlaysWorld) {
_overlaysToDelete.push_back(overlay); _overlaysToDelete.push_back(overlay);
} }
cleanupOverlaysToDelete(); cleanupOverlaysToDelete();
@ -77,10 +72,7 @@ void Overlays::init() {
void Overlays::update(float deltatime) { void Overlays::update(float deltatime) {
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
foreach(const auto& thisOverlay, _overlaysHUD) { foreach(const auto& thisOverlay, _overlays) {
thisOverlay->update(deltatime);
}
foreach(const auto& thisOverlay, _overlaysWorld) {
thisOverlay->update(deltatime); thisOverlay->update(deltatime);
} }
} }
@ -110,7 +102,7 @@ void Overlays::cleanupOverlaysToDelete() {
} }
} }
void Overlays::renderHUD(RenderArgs* renderArgs) { void Overlays::render(RenderArgs* renderArgs) {
PROFILE_RANGE(render_overlays, __FUNCTION__); PROFILE_RANGE(render_overlays, __FUNCTION__);
gpu::Batch& batch = *renderArgs->_batch; gpu::Batch& batch = *renderArgs->_batch;
@ -123,7 +115,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000); mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { foreach(Overlay::Pointer thisOverlay, _overlays) {
// Reset all batch pipeline settings between overlay // Reset all batch pipeline settings between overlay
geometryCache->useSimpleDrawPipeline(batch); geometryCache->useSimpleDrawPipeline(batch);
@ -146,29 +138,28 @@ void Overlays::enable() {
// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder // Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder
// class on packet processing threads // class on packet processing threads
Overlay::Pointer Overlays::getOverlay(OverlayID id) const { Overlay::Pointer Overlays::get2DOverlay(const QUuid& id) const {
if (_shuttingDown) { if (_shuttingDown) {
return nullptr; return nullptr;
} }
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) { auto overlayIter = _overlays.find(id);
return _overlaysHUD[id]; if (overlayIter != _overlays.end()) {
} else if (_overlaysWorld.contains(id)) { return overlayIter.value();
return _overlaysWorld[id];
} }
return nullptr; return nullptr;
} }
OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) { QUuid Overlays::addOverlay(const QString& type, const QVariant& properties) {
if (_shuttingDown) { if (_shuttingDown) {
return UNKNOWN_OVERLAY_ID; return UNKNOWN_OVERLAY_ID;
} }
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
OverlayID result; QUuid result;
PROFILE_RANGE(script, __FUNCTION__); PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(QString, type), Q_ARG(QVariant, properties)); BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(QUuid, result), Q_ARG(const QString&, type), Q_ARG(const QVariant&, properties));
return result; return result;
} }
@ -267,58 +258,69 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties)
if (thisOverlay) { if (thisOverlay) {
thisOverlay->setProperties(properties.toMap()); thisOverlay->setProperties(properties.toMap());
return addOverlay(thisOverlay); return add2DOverlay(thisOverlay);
} }
return UNKNOWN_OVERLAY_ID; return UNKNOWN_OVERLAY_ID;
} }
OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { QUuid Overlays::add2DOverlay(const Overlay::Pointer& overlay) {
if (_shuttingDown) { if (_shuttingDown) {
return UNKNOWN_OVERLAY_ID; return UNKNOWN_OVERLAY_ID;
} }
OverlayID thisID = OverlayID(QUuid::createUuid()); QUuid thisID = QUuid::createUuid();
overlay->setOverlayID(thisID); overlay->setOverlayID(thisID);
overlay->setStackOrder(_stackOrder++); overlay->setStackOrder(_stackOrder++);
if (overlay->is3D()) { {
{
QMutexLocker locker(&_mutex);
_overlaysWorld[thisID] = overlay;
}
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
overlay->addToScene(overlay, scene, transaction);
scene->enqueueTransaction(transaction);
} else {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
_overlaysHUD[thisID] = overlay; _overlays[thisID] = overlay;
} }
return thisID; return thisID;
} }
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { QUuid Overlays::cloneOverlay(const QUuid& id) {
if (_shuttingDown) {
return UNKNOWN_OVERLAY_ID;
}
if (QThread::currentThread() != thread()) {
QUuid result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "cloneOverlay", Q_RETURN_ARG(QUuid, result), Q_ARG(const QUuid&, id));
return result;
}
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
return add2DOverlay(Overlay::Pointer(overlay->createClone(), [](Overlay* ptr) { ptr->deleteLater(); }));
}
return DependencyManager::get<EntityScriptingInterface>()->cloneEntity(id);
}
bool Overlays::editOverlay(const QUuid& id, const QVariant& properties) {
if (_shuttingDown) { if (_shuttingDown) {
return false; return false;
} }
auto thisOverlay = getOverlay(id); auto overlay = get2DOverlay(id);
if (!thisOverlay) { if (overlay) {
return false; if (QThread::currentThread() != thread()) {
} // NOTE editOverlay can be called very frequently in scripts and can't afford to
// block waiting on the main thread. Additionally, no script actually
// examines the return value and does something useful with it, so use a non-blocking
// invoke and just always return true
QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(const QUuid&, id), Q_ARG(const QVariant&, properties));
return true;
}
if (!thisOverlay->is3D() && QThread::currentThread() != thread()) { overlay->setProperties(properties.toMap());
// NOTE editOverlay can be called very frequently in scripts and can't afford to
// block waiting on the main thread. Additionally, no script actually
// examines the return value and does something useful with it, so use a non-blocking
// invoke and just always return true
QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
return true; return true;
} }
thisOverlay->setProperties(properties.toMap()); EntityItemProperties entityProperties = convertOverlayToEntityProperties(properties.toMap());
return true; return !DependencyManager::get<EntityScriptingInterface>()->editEntity(id, entityProperties).isNull();
} }
bool Overlays::editOverlays(const QVariant& propertiesById) { bool Overlays::editOverlays(const QVariant& propertiesById) {
@ -326,165 +328,166 @@ bool Overlays::editOverlays(const QVariant& propertiesById) {
return false; return false;
} }
bool defer2DOverlays = QThread::currentThread() != thread(); bool deferOverlays = QThread::currentThread() != thread();
QVariantMap deferrred; QVariantMap deferred;
const QVariantMap map = propertiesById.toMap(); const QVariantMap map = propertiesById.toMap();
bool success = true;
for (const auto& key : map.keys()) { for (const auto& key : map.keys()) {
OverlayID id = OverlayID(key); QUuid id = QUuid(key);
Overlay::Pointer thisOverlay = getOverlay(id);
if (!thisOverlay) {
success = false;
continue;
}
const QVariant& properties = map[key]; const QVariant& properties = map[key];
if (defer2DOverlays && !thisOverlay->is3D()) {
deferrred[key] = properties; Overlay::Pointer overlay = get2DOverlay(id);
continue; if (overlay) {
if (deferOverlays) {
deferred[key] = properties;
continue;
}
overlay->setProperties(properties.toMap());
} else {
EntityItemProperties entityProperties = convertOverlayToEntityProperties(properties.toMap());
DependencyManager::get<EntityScriptingInterface>()->editEntity(id, entityProperties);
} }
thisOverlay->setProperties(properties.toMap());
} }
// For 2D/QML overlays, we need to perform the edit on the main thread // For 2D/QML overlays, we need to perform the edit on the main thread
if (defer2DOverlays && !deferrred.empty()) { if (!deferred.empty()) {
// NOTE see comment on editOverlay for why this is not a blocking call // NOTE see comment on editOverlay for why this is not a blocking call
QMetaObject::invokeMethod(this, "editOverlays", Q_ARG(QVariant, deferrred)); QMetaObject::invokeMethod(this, "editOverlays", Q_ARG(const QVariant&, deferred));
} }
return success; return true;
} }
void Overlays::deleteOverlay(EntityItemID id) { void Overlays::deleteOverlay(const QUuid& id) {
if (_shuttingDown) { if (_shuttingDown) {
return; return;
} }
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
_overlaysToDelete.push_back(overlay);
emit overlayDeleted(id);
return;
}
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(id); DependencyManager::get<EntityScriptingInterface>()->deleteEntity(id);
emit overlayDeleted(id); emit overlayDeleted(id);
} }
QString Overlays::getOverlayType(OverlayID overlayId) { QString Overlays::getOverlayType(const QUuid& id) {
if (_shuttingDown) { if (_shuttingDown) {
return ""; return "";
} }
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QString result; QString result;
PROFILE_RANGE(script, __FUNCTION__); PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(OverlayID, overlayId)); BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(const QUuid&, id));
return result; return result;
} }
Overlay::Pointer overlay = getOverlay(overlayId); Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) { if (overlay) {
return overlay->getType(); return overlay->getType();
} }
return "";
return entityToOverlayType(DependencyManager::get<EntityScriptingInterface>()->getEntityType(id));
} }
QObject* Overlays::getOverlayObject(OverlayID id) { QObject* Overlays::getOverlayObject(const QUuid& id) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QObject* result; QObject* result;
PROFILE_RANGE(script, __FUNCTION__); PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id)); BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(const QUuid&, id));
return result; return result;
} }
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer overlay = get2DOverlay(id);
if (thisOverlay) { if (overlay) {
return qobject_cast<QObject*>(&(*thisOverlay)); return qobject_cast<QObject*>(&(*overlay));
} }
return nullptr;
return DependencyManager::get<EntityScriptingInterface>()->getEntityObject(id);
} }
OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { QUuid Overlays::getOverlayAtPoint(const glm::vec2& point) {
if (_shuttingDown || !_enabled) { if (_shuttingDown || !_enabled) {
return UNKNOWN_OVERLAY_ID; return UNKNOWN_ENTITY_ID;
} }
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD); QMapIterator<QUuid, Overlay::Pointer> i(_overlays);
unsigned int bestStackOrder = 0; unsigned int bestStackOrder = 0;
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID; QUuid bestID = UNKNOWN_ENTITY_ID;
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value()); auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() && if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
thisOverlay->getBoundingRect().contains(point.x, point.y, false)) { thisOverlay->getBoundingRect().contains(point.x, point.y, false)) {
if (thisOverlay->getStackOrder() > bestStackOrder) { if (thisOverlay->getStackOrder() > bestStackOrder) {
bestOverlayID = i.key(); bestID = i.key();
bestStackOrder = thisOverlay->getStackOrder(); bestStackOrder = thisOverlay->getStackOrder();
} }
} }
} }
return bestOverlayID; return bestID;
} }
OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) { QVariant Overlays::getProperty(const QUuid& id, const QString& property) {
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer overlay = get2DOverlay(id);
OverlayPropertyResult result; if (overlay) {
if (thisOverlay && thisOverlay->supportsGetProperty()) { if (overlay->supportsGetProperty()) {
result.value = thisOverlay->getProperty(property); return overlay->getProperty(property);
}
return result;
}
OverlayPropertyResult Overlays::getProperties(const OverlayID& id, const QStringList& properties) {
Overlay::Pointer thisOverlay = getOverlay(id);
OverlayPropertyResult result;
if (thisOverlay && thisOverlay->supportsGetProperty()) {
QVariantMap mapResult;
for (const auto& property : properties) {
mapResult.insert(property, thisOverlay->getProperty(property));
} }
result.value = mapResult; return QVariant();
} }
return result;
QVariantMap overlayProperties = convertEntityToOverlayProperties(DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id));
auto propIter = overlayProperties.find(property);
if (propIter != overlayProperties.end()) {
return propIter.value();
}
return QVariant();
} }
OverlayPropertyResult Overlays::getOverlaysProperties(const QVariant& propertiesById) { QVariantMap Overlays::getProperties(const QUuid& id, const QStringList& properties) {
QVariantMap map = propertiesById.toMap(); Overlay::Pointer overlay = get2DOverlay(id);
OverlayPropertyResult result; QVariantMap result;
QVariantMap resultMap; if (overlay) {
for (const auto& key : map.keys()) { if (overlay->supportsGetProperty()) {
OverlayID id = OverlayID(key); for (const auto& property : properties) {
QVariantMap overlayResult; result.insert(property, overlay->getProperty(property));
Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay && thisOverlay->supportsGetProperty()) {
QStringList propertiesToFetch = map[key].toStringList();
for (const auto& property : propertiesToFetch) {
overlayResult[property] = thisOverlay->getProperty(property);
} }
} }
resultMap[key] = overlayResult; return result;
}
QVariantMap overlayProperties = convertEntityToOverlayProperties(DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id));
for (const auto& property : properties) {
auto propIter = overlayProperties.find(property);
if (propIter != overlayProperties.end()) {
result.insert(property, propIter.value());
}
} }
result.value = resultMap;
return result; return result;
} }
OverlayPropertyResult::OverlayPropertyResult() { QVariantMap Overlays::getOverlaysProperties(const QVariant& propertiesById) {
} QVariantMap map = propertiesById.toMap();
QVariantMap result;
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value) { for (const auto& key : map.keys()) {
if (!value.value.isValid()) { result[key] = getProperties(QUuid(key), map[key].toStringList());
return QScriptValue::UndefinedValue;
} }
return engine->toScriptValue(value.value); return result;
} }
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value) {
value.value = object.toVariant();
}
RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, bool precisionPicking, RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, bool precisionPicking,
const QScriptValue& overlayIDsToInclude, const QScriptValue& overlayIDsToInclude,
const QScriptValue& overlayIDsToDiscard, const QScriptValue& overlayIDsToDiscard,
bool visibleOnly, bool collidableOnly) { bool visibleOnly, bool collidableOnly) {
const QVector<OverlayID> overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude); const QVector<QUuid> overlaysToInclude = qVectorQUuidFromScriptValue(overlayIDsToInclude);
const QVector<OverlayID> overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard); const QVector<QUuid> overlaysToDiscard = qVectorQUuidFromScriptValue(overlayIDsToDiscard);
return findRayIntersectionVector(ray, precisionPicking, return findRayIntersectionVector(ray, precisionPicking,
overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly); overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly);
@ -492,8 +495,8 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray,
RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay& ray, bool precisionPicking, RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude, const QVector<QUuid>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard, const QVector<QUuid>& overlaysToDiscard,
bool visibleOnly, bool collidableOnly) { bool visibleOnly, bool collidableOnly) {
float bestDistance = std::numeric_limits<float>::max(); float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false; bool bestIsFront = false;
@ -624,77 +627,71 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
value.extraInfo = object.property("extraInfo").toVariant().toMap(); value.extraInfo = object.property("extraInfo").toVariant().toMap();
} }
bool Overlays::isLoaded(OverlayID id) { bool Overlays::isLoaded(const QUuid& id) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
bool result; bool result;
PROFILE_RANGE(script, __FUNCTION__); PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id)); BLOCKING_INVOKE_METHOD(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(const QUuid&, id));
return result; return result;
} }
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer overlay = get2DOverlay(id);
if (!thisOverlay) { if (overlay) {
return false; // not found return overlay->isLoaded();
} }
return thisOverlay->isLoaded();
return DependencyManager::get<EntityScriptingInterface>()->isLoaded(id);
} }
QSizeF Overlays::textSize(OverlayID id, const QString& text) { QSizeF Overlays::textSize(const QUuid& id, const QString& text) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QSizeF result; QSizeF result;
PROFILE_RANGE(script, __FUNCTION__); PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(OverlayID, id), Q_ARG(QString, text)); BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(const QUuid&, id), Q_ARG(QString, text));
return result; return result;
} }
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer overlay = get2DOverlay(id);
if (thisOverlay) { if (overlay) {
if (thisOverlay->is3D()) { if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(overlay)) {
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) { return textOverlay->textSize(text);
return text3dOverlay->textSize(text);
}
} else {
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
return textOverlay->textSize(text);
}
} }
return QSizeF(0.0f, 0.0f);
} else {
return DependencyManager::get<EntityScriptingInterface>()->textSize(id, text);
} }
return QSizeF(0.0f, 0.0f);
} }
bool Overlays::isAddedOverlay(OverlayID id) { bool Overlays::isAddedOverlay(const QUuid& id) {
if (QThread::currentThread() != thread()) { Overlay::Pointer overlay = get2DOverlay(id);
bool result; if (overlay) {
PROFILE_RANGE(script, __FUNCTION__); return true;
BLOCKING_INVOKE_METHOD(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
return result;
} }
QMutexLocker locker(&_mutex); return DependencyManager::get<EntityScriptingInterface>()->isAddedEntity(id);
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
} }
void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { void Overlays::sendMousePressOnOverlay(const QUuid& overlayID, const PointerEvent& event) {
mousePressPointerEvent(overlayID, event); mousePressPointerEvent(overlayID, event);
} }
void Overlays::sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { void Overlays::sendMouseReleaseOnOverlay(const QUuid& overlayID, const PointerEvent& event) {
mouseReleasePointerEvent(overlayID, event); mouseReleasePointerEvent(overlayID, event);
} }
void Overlays::sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { void Overlays::sendMouseMoveOnOverlay(const QUuid& overlayID, const PointerEvent& event) {
mouseMovePointerEvent(overlayID, event); mouseMovePointerEvent(overlayID, event);
} }
void Overlays::sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event) { void Overlays::sendHoverEnterOverlay(const QUuid& overlayID, const PointerEvent& event) {
hoverEnterPointerEvent(overlayID, event); hoverEnterPointerEvent(overlayID, event);
} }
void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) { void Overlays::sendHoverOverOverlay(const QUuid& overlayID, const PointerEvent& event) {
hoverOverPointerEvent(overlayID, event); hoverOverPointerEvent(overlayID, event);
} }
void Overlays::sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) { void Overlays::sendHoverLeaveOverlay(const QUuid& overlayID, const PointerEvent& event) {
hoverLeavePointerEvent(overlayID, event); hoverLeavePointerEvent(overlayID, event);
} }
@ -765,10 +762,10 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
} }
} }
PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, PointerEvent Overlays::calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray,
RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event, const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event,
PointerEvent::EventType eventType) { PointerEvent::EventType eventType) {
auto overlay = std::dynamic_pointer_cast<Planar3DOverlay>(getOverlay(overlayID)); auto overlay = std::dynamic_pointer_cast<Planar3DOverlay>(getOverlay(id));
if (getOverlayType(overlayID) == "web3d") { if (getOverlayType(overlayID) == "web3d") {
overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(overlayID)); overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
} }
@ -793,8 +790,7 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mousePressEvent"); PerformanceTimer perfTimer("Overlays::mousePressEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y()); PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<OverlayID>(), RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<QUuid>(), QVector<QUuid>());
QVector<OverlayID>());
if (rayPickResult.intersects) { if (rayPickResult.intersects) {
_currentClickingOnOverlayID = rayPickResult.overlayID; _currentClickingOnOverlayID = rayPickResult.overlayID;
@ -839,8 +835,7 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y()); PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<OverlayID>(), RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<OverlayID>(), QVector<OverlayID>());
QVector<OverlayID>());
if (rayPickResult.intersects) { if (rayPickResult.intersects) {
_currentClickingOnOverlayID = rayPickResult.overlayID; _currentClickingOnOverlayID = rayPickResult.overlayID;

View file

@ -32,19 +32,6 @@
class PickRay; class PickRay;
class OverlayPropertyResult {
public:
OverlayPropertyResult();
QVariant value;
};
Q_DECLARE_METATYPE(OverlayPropertyResult);
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value);
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value);
const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
/**jsdoc /**jsdoc
* The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}. * The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}.
* @typedef {object} Overlays.RayToOverlayIntersectionResult * @typedef {object} Overlays.RayToOverlayIntersectionResult
@ -59,7 +46,7 @@ const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
class RayToOverlayIntersectionResult { class RayToOverlayIntersectionResult {
public: public:
bool intersects { false }; bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID }; QUuid overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0.0f }; float distance { 0.0f };
BoxFace face { UNKNOWN_FACE }; BoxFace face { UNKNOWN_FACE };
glm::vec3 surfaceNormal; glm::vec3 surfaceNormal;
@ -73,7 +60,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
class ParabolaToOverlayIntersectionResult { class ParabolaToOverlayIntersectionResult {
public: public:
bool intersects { false }; bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID }; QUuid overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0.0f }; float distance { 0.0f };
float parabolicDistance { 0.0f }; float parabolicDistance { 0.0f };
BoxFace face { UNKNOWN_FACE }; BoxFace face { UNKNOWN_FACE };
@ -83,7 +70,7 @@ public:
}; };
/**jsdoc /**jsdoc
* Deprecated. Use local entities instead. The Overlays API provides facilities to create and interact with overlays. Overlays are 2D and 3D objects visible only to * (Note: 3D Overlays are deprecated. Use local entities instead.) The Overlays API provides facilities to create and interact with overlays. Overlays are 2D and 3D objects visible only to
* yourself and that aren't persisted to the domain. They are used for UI. * yourself and that aren't persisted to the domain. They are used for UI.
* @namespace Overlays * @namespace Overlays
* *
@ -98,31 +85,31 @@ public:
class Overlays : public QObject { class Overlays : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(OverlayID keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay) Q_PROPERTY(QUuid keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay)
public: public:
Overlays(); Overlays();
void init(); void init();
void update(float deltatime); void update(float deltatime);
void renderHUD(RenderArgs* renderArgs); void render(RenderArgs* renderArgs);
void disable(); void disable();
void enable(); void enable();
Overlay::Pointer getOverlay(OverlayID id) const; Overlay::Pointer get2DOverlay(const QUuid& id) const;
/// adds an overlay that's already been created /// adds an overlay that's already been created
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } QUuid addOverlay(Overlay* overlay) { return add2DOverlay(Overlay::Pointer(overlay)); }
OverlayID addOverlay(const Overlay::Pointer& overlay); QUuid add2DOverlay(const Overlay::Pointer& overlay);
RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking, RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude, const QVector<QUuid>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard, const QVector<QUuid>& overlaysToDiscard,
bool visibleOnly = false, bool collidableOnly = false); bool visibleOnly = false, bool collidableOnly = false);
ParabolaToOverlayIntersectionResult findParabolaIntersectionVector(const PickParabola& parabola, bool precisionPicking, ParabolaToOverlayIntersectionResult findParabolaIntersectionVector(const PickParabola& parabola, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude, const QVector<QUuid>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard, const QVector<QUuid>& overlaysToDiscard,
bool visibleOnly = false, bool collidableOnly = false); bool visibleOnly = false, bool collidableOnly = false);
bool mousePressEvent(QMouseEvent* event); bool mousePressEvent(QMouseEvent* event);
@ -147,20 +134,20 @@ public slots:
* solid: true * solid: true
* }); * });
*/ */
OverlayID addOverlay(const QString& type, const QVariant& properties); QUuid addOverlay(const QString& type, const QVariant& properties);
/**jsdoc /**jsdoc
* Create a clone of an existing entity. * Create a clone of an existing entity (or 2D overlay).
* @function Overlays.cloneOverlay * @function Overlays.cloneOverlay
* @param {Uuid} id - The ID of the entity to clone. * @param {Uuid} id - The ID of the entity/2D overlay to clone.
* @returns {Uuid} The ID of the new entity if successful, otherwise {@link Uuid|Uuid.NULL}. * @returns {Uuid} The ID of the new object if successful, otherwise {@link Uuid|Uuid.NULL}.
*/ */
EntityItemID cloneOverlay(EntityItemID id) { return DependencyManager::get<EntityScriptingInterface>()->cloneEntity(id); } QUuid cloneOverlay(const QUuid& id);
/**jsdoc /**jsdoc
* Edit an overlay's properties. * Edit an overlay's properties.
* @function Overlays.editOverlay * @function Overlays.editOverlay
* @param {Uuid} overlayID - The ID of the overlay to edit. * @param {Uuid} id - The ID of the overlay to edit.
* @param {Overlays.OverlayProperties} properties - The properties changes to make. * @param {Overlays.OverlayProperties} properties - The properties changes to make.
* @returns {boolean} <code>true</code> if the overlay was found and edited, otherwise <code>false</code>. * @returns {boolean} <code>true</code> if the overlay was found and edited, otherwise <code>false</code>.
* @example <caption>Add an overlay in front of your avatar then change its color.</caption> * @example <caption>Add an overlay in front of your avatar then change its color.</caption>
@ -176,7 +163,7 @@ public slots:
* }); * });
* print("Success: " + success); * print("Success: " + success);
*/ */
bool editOverlay(OverlayID id, const QVariant& properties); bool editOverlay(const QUuid& id, const QVariant& properties);
/**jsdoc /**jsdoc
* Edit multiple overlays' properties. * Edit multiple overlays' properties.
@ -208,18 +195,18 @@ public slots:
bool editOverlays(const QVariant& propertiesById); bool editOverlays(const QVariant& propertiesById);
/**jsdoc /**jsdoc
* Delete an entity. * Delete an entity or 2D overlay.
* @function Overlays.deleteOverlay * @function Overlays.deleteOverlay
* @param {Uuid} id - The ID of the entity to delete. * @param {Uuid} id - The ID of the object to delete.
*/ */
void deleteOverlay(EntityItemID id); void deleteOverlay(const QUuid& id);
/**jsdoc /**jsdoc
* Get the type of an overlay. * Get the type of an entity or 2D overlay.
* @function Overlays.getOverlayType * @function Overlays.getOverlayType
* @param {Uuid} overlayID - The ID of the overlay to get the type of. * @param {Uuid} id - The ID of the object to get the type of.
* @returns {Overlays.OverlayType} The type of the overlay if found, otherwise an empty string. * @returns {string} The type of the object if found, otherwise an empty string.
* @example <caption>Create an overlay in front of your avatar then get and report its type.</caption> * @example <caption>Create an object in front of your avatar then get and report its type.</caption>
* var overlay = Overlays.addOverlay("cube", { * var overlay = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })), * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
* rotation: MyAvatar.orientation, * rotation: MyAvatar.orientation,
@ -229,7 +216,7 @@ public slots:
* var type = Overlays.getOverlayType(overlay); * var type = Overlays.getOverlayType(overlay);
* print("Type: " + type); * print("Type: " + type);
*/ */
QString getOverlayType(OverlayID overlayId); QString getOverlayType(const QUuid& id);
/**jsdoc /**jsdoc
* Get the overlay script object. In particular, this is useful for accessing the event bridge for a <code>web3d</code> * Get the overlay script object. In particular, this is useful for accessing the event bridge for a <code>web3d</code>
@ -273,7 +260,7 @@ public slots:
* Overlays.deleteOverlay(web3dOverlay); * Overlays.deleteOverlay(web3dOverlay);
* }); * });
*/ */
QObject* getOverlayObject(OverlayID id); QObject* getOverlayObject(const QUuid& id);
/**jsdoc /**jsdoc
* Get the ID of the 2D overlay at a particular point on the screen or HUD. * Get the ID of the 2D overlay at a particular point on the screen or HUD.
@ -292,12 +279,12 @@ public slots:
* print("Clicked: " + overlay); * print("Clicked: " + overlay);
* }); * });
*/ */
OverlayID getOverlayAtPoint(const glm::vec2& point); QUuid getOverlayAtPoint(const glm::vec2& point);
/**jsdoc /**jsdoc
* Get the value of a 3D overlay's property. * Get the value of a 3D overlay's property.
* @function Overlays.getProperty * @function Overlays.getProperty
* @param {Uuid} overlayID - The ID of the overlay. <em>Must be for a 3D {@link Overlays.OverlayType|OverlayType}.</em> * @param {Uuid} id - The ID of the overlay. <em>Must be for a 3D {@link Overlays.OverlayType|OverlayType}.</em>
* @param {string} property - The name of the property value to get. * @param {string} property - The name of the property value to get.
* @returns {object} The value of the property if the 3D overlay and property can be found, otherwise * @returns {object} The value of the property if the 3D overlay and property can be found, otherwise
* <code>undefined</code>. * <code>undefined</code>.
@ -311,12 +298,12 @@ public slots:
* var alpha = Overlays.getProperty(overlay, "alpha"); * var alpha = Overlays.getProperty(overlay, "alpha");
* print("Overlay alpha: " + alpha); * print("Overlay alpha: " + alpha);
*/ */
OverlayPropertyResult getProperty(OverlayID id, const QString& property); QVariant getProperty(const QUuid& id, const QString& property);
/**jsdoc /**jsdoc
* Get the values of an overlay's properties. * Get the values of an overlay's properties.
* @function Overlays.getProperties * @function Overlays.getProperties
* @param {Uuid} overlayID - The ID of the overlay. * @param {Uuid} id - The ID of the overlay.
* @param {Array.<string>} properties - An array of names of properties to get the values of. * @param {Array.<string>} properties - An array of names of properties to get the values of.
* @returns {Overlays.OverlayProperties} The values of valid properties if the overlay can be found, otherwise * @returns {Overlays.OverlayProperties} The values of valid properties if the overlay can be found, otherwise
* <code>undefined</code>. * <code>undefined</code>.
@ -330,7 +317,7 @@ public slots:
* var properties = Overlays.getProperties(overlay, ["color", "alpha", "grabbable"]); * var properties = Overlays.getProperties(overlay, ["color", "alpha", "grabbable"]);
* print("Overlay properties: " + JSON.stringify(properties)); * print("Overlay properties: " + JSON.stringify(properties));
*/ */
OverlayPropertyResult getProperties(const OverlayID& id, const QStringList& properties); QVariantMap getProperties(const QUuid& id, const QStringList& properties);
/**jsdoc /**jsdoc
* Get the values of multiple overlays' properties. * Get the values of multiple overlays' properties.
@ -358,7 +345,7 @@ public slots:
* var properties = Overlays.getOverlaysProperties(propertiesToGet); * var properties = Overlays.getOverlaysProperties(propertiesToGet);
* print("Overlays properties: " + JSON.stringify(properties)); * print("Overlays properties: " + JSON.stringify(properties));
*/ */
OverlayPropertyResult getOverlaysProperties(const QVariant& overlaysProperties); QVariantMap getOverlaysProperties(const QVariant& overlaysProperties);
/**jsdoc /**jsdoc
* Find the closest 3D overlay intersected by a {@link PickRay}. Overlays with their <code>drawInFront</code> property set * Find the closest 3D overlay intersected by a {@link PickRay}. Overlays with their <code>drawInFront</code> property set
@ -428,7 +415,7 @@ public slots:
* Check whether an overlay's assets have been loaded. For example, for an <code>image</code> overlay the result indicates * Check whether an overlay's assets have been loaded. For example, for an <code>image</code> overlay the result indicates
* whether its image has been loaded. * whether its image has been loaded.
* @function Overlays.isLoaded * @function Overlays.isLoaded
* @param {Uuid} overlayID - The ID of the overlay to check. * @param {Uuid} id - The ID of the overlay to check.
* @returns {boolean} <code>true</code> if the overlay's assets have been loaded, otherwise <code>false</code>. * @returns {boolean} <code>true</code> if the overlay's assets have been loaded, otherwise <code>false</code>.
* @example <caption>Create an image overlay and report whether its image is loaded after 1s.</caption> * @example <caption>Create an image overlay and report whether its image is loaded after 1s.</caption>
* var overlay = Overlays.addOverlay("image", { * var overlay = Overlays.addOverlay("image", {
@ -440,17 +427,17 @@ public slots:
* print("Image loaded: " + isLoaded); * print("Image loaded: " + isLoaded);
* }, 1000); * }, 1000);
*/ */
bool isLoaded(OverlayID id); bool isLoaded(const QUuid& id);
/**jsdoc /**jsdoc
* Calculates the size of the given text in the specified overlay if it is a text overlay. * Calculates the size of the given text in the specified object if it is a text entity or overlay.
* @function Overlays.textSize * @function Overlays.textSize
* @param {Uuid} overlayID - The ID of the overlay to use for calculation. * @param {Uuid} id - The ID of the object to use for calculation.
* @param {string} text - The string to calculate the size of. * @param {string} text - The string to calculate the size of.
* @returns {Size} The size of the <code>text</code> if the overlay is a text overlay, otherwise * @returns {Size} The size of the <code>text</code> if the object is a text entity or overlay, otherwise
* <code>{ height: 0, width : 0 }</code>. If the overlay is a 2D overlay, the size is in pixels; if the overlay is a 3D * <code>{ height: 0, width : 0 }</code>. If the object is a 2D overlay, the size is in pixels; if the object is an entity,
* overlay, the size is in meters. * the size is in meters.
* @example <caption>Calculate the size of "hello" in a 3D text overlay.</caption> * @example <caption>Calculate the size of "hello" in a 3D text entity.</caption>
* var overlay = Overlays.addOverlay("text3d", { * var overlay = Overlays.addOverlay("text3d", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })), * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })),
* rotation: MyAvatar.orientation, * rotation: MyAvatar.orientation,
@ -460,7 +447,7 @@ public slots:
* var textSize = Overlays.textSize(overlay, "hello"); * var textSize = Overlays.textSize(overlay, "hello");
* print("Size of \"hello\": " + JSON.stringify(textSize)); * print("Size of \"hello\": " + JSON.stringify(textSize));
*/ */
QSizeF textSize(OverlayID id, const QString& text); QSizeF textSize(const QUuid& id, const QString& text);
/**jsdoc /**jsdoc
* Get the width of the window or HUD. * Get the width of the window or HUD.
@ -477,17 +464,17 @@ public slots:
float height(); float height();
/**jsdoc /**jsdoc
* Check if there is an overlay of a given ID. * Check if there is an object of a given ID.
* @function Overlays.isAddedOverlay * @function Overlays.isAddedOverlay
* @param {Uuid} overlayID - The ID to check. * @param {Uuid} id - The ID to check.
* @returns {boolean} <code>true</code> if an overlay with the given ID exists, <code>false</code> otherwise. * @returns {boolean} <code>true</code> if an object with the given ID exists, <code>false</code> otherwise.
*/ */
bool isAddedOverlay(OverlayID id); bool isAddedOverlay(const QUuid& id);
/**jsdoc /**jsdoc
* Generate a mouse press event on an overlay. * Generate a mouse press event on an overlay.
* @function Overlays.sendMousePressOnOverlay * @function Overlays.sendMousePressOnOverlay
* @param {Uuid} overlayID - The ID of the overlay to generate a mouse press event on. * @param {Uuid} id - The ID of the overlay to generate a mouse press event on.
* @param {PointerEvent} event - The mouse press event details. * @param {PointerEvent} event - The mouse press event details.
* @example <caption>Create a 2D rectangle overlay plus a 3D cube overlay and generate mousePressOnOverlay events for the 2D * @example <caption>Create a 2D rectangle overlay plus a 3D cube overlay and generate mousePressOnOverlay events for the 2D
* overlay.</caption> * overlay.</caption>
@ -522,23 +509,23 @@ public slots:
* } * }
* }); * });
*/ */
void sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendMousePressOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Generate a mouse release event on an overlay. * Generate a mouse release event on an overlay.
* @function Overlays.sendMouseReleaseOnOverlay * @function Overlays.sendMouseReleaseOnOverlay
* @param {Uuid} overlayID - The ID of the overlay to generate a mouse release event on. * @param {Uuid} id - The ID of the overlay to generate a mouse release event on.
* @param {PointerEvent} event - The mouse release event details. * @param {PointerEvent} event - The mouse release event details.
*/ */
void sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendMouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Generate a mouse move event on an overlay. * Generate a mouse move event on an overlay.
* @function Overlays.sendMouseMoveOnOverlay * @function Overlays.sendMouseMoveOnOverlay
* @param {Uuid} overlayID - The ID of the overlay to generate a mouse move event on. * @param {Uuid} id - The ID of the overlay to generate a mouse move event on.
* @param {PointerEvent} event - The mouse move event details. * @param {PointerEvent} event - The mouse move event details.
*/ */
void sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendMouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Generate a hover enter event on an overlay. * Generate a hover enter event on an overlay.
@ -546,23 +533,23 @@ public slots:
* @param {Uuid} id - The ID of the overlay to generate a hover enter event on. * @param {Uuid} id - The ID of the overlay to generate a hover enter event on.
* @param {PointerEvent} event - The hover enter event details. * @param {PointerEvent} event - The hover enter event details.
*/ */
void sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendHoverEnterOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Generate a hover over event on an overlay. * Generate a hover over event on an overlay.
* @function Overlays.sendHoverOverOverlay * @function Overlays.sendHoverOverOverlay
* @param {Uuid} overlayID - The ID of the overlay to generate a hover over event on. * @param {Uuid} id - The ID of the overlay to generate a hover over event on.
* @param {PointerEvent} event - The hover over event details. * @param {PointerEvent} event - The hover over event details.
*/ */
void sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendHoverOverOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Generate a hover leave event on an overlay. * Generate a hover leave event on an overlay.
* @function Overlays.sendHoverLeaveOverlay * @function Overlays.sendHoverLeaveOverlay
* @param {Uuid} overlayID - The ID of the overlay to generate a hover leave event on. * @param {Uuid} id - The ID of the overlay to generate a hover leave event on.
* @param {PointerEvent} event - The hover leave event details. * @param {PointerEvent} event - The hover leave event details.
*/ */
void sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendHoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Get the ID of the Web3D local entity that has keyboard focus. * Get the ID of the Web3D local entity that has keyboard focus.
@ -575,16 +562,16 @@ public slots:
/**jsdoc /**jsdoc
* Set the Web3D local entity that has keyboard focus. * Set the Web3D local entity that has keyboard focus.
* @function Overlays.setKeyboardFocusOverlay * @function Overlays.setKeyboardFocusOverlay
* @param {Uuid} overlayID - The ID of the {@link Entities.EntityTypes|Web} overlay to set keyboard focus to. Use * @param {Uuid} id - The ID of the {@link Entities.EntityTypes|Web} overlay to set keyboard focus to. Use
* <code>null</code> or {@link Uuid|Uuid.NULL} to unset keyboard focus from an overlay. * <code>null</code> or {@link Uuid|Uuid.NULL} to unset keyboard focus from an overlay.
*/ */
void Overlays::setKeyboardFocusOverlay(const EntityItemID& id) { DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusLocalEntity(id); } void setKeyboardFocusOverlay(const EntityItemID& id) { DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusLocalEntity(id); }
signals: signals:
/**jsdoc /**jsdoc
* Triggered when an overlay is deleted. * Triggered when an overlay is deleted.
* @function Overlays.overlayDeleted * @function Overlays.overlayDeleted
* @param {Uuid} overlayID - The ID of the overlay that was deleted. * @param {Uuid} id - The ID of the overlay that was deleted.
* @returns {Signal} * @returns {Signal}
* @example <caption>Create an overlay then delete it after 1s.</caption> * @example <caption>Create an overlay then delete it after 1s.</caption>
* var overlay = Overlays.addOverlay("cube", { * var overlay = Overlays.addOverlay("cube", {
@ -602,13 +589,13 @@ signals:
* Overlays.deleteOverlay(overlay); * Overlays.deleteOverlay(overlay);
* }, 1000); * }, 1000);
*/ */
void overlayDeleted(OverlayID id); void overlayDeleted(const QUuid& id);
/**jsdoc /**jsdoc
* Triggered when a mouse press event occurs on an overlay. Only occurs for 3D overlays (unless you use * Triggered when a mouse press event occurs on an overlay. Only occurs for 3D overlays (unless you use
* {@link Overlays.sendMousePressOnOverlay|sendMousePressOnOverlay} for a 2D overlay). * {@link Overlays.sendMousePressOnOverlay|sendMousePressOnOverlay} for a 2D overlay).
* @function Overlays.mousePressOnOverlay * @function Overlays.mousePressOnOverlay
* @param {Uuid} overlayID - The ID of the overlay the mouse press event occurred on. * @param {Uuid} id - The ID of the overlay the mouse press event occurred on.
* @param {PointerEvent} event - The mouse press event details. * @param {PointerEvent} event - The mouse press event details.
* @returns {Signal} * @returns {Signal}
* @example <caption>Create a cube overlay in front of your avatar and report mouse clicks on it.</caption> * @example <caption>Create a cube overlay in front of your avatar and report mouse clicks on it.</caption>
@ -626,36 +613,36 @@ signals:
* } * }
* }); * });
*/ */
void mousePressOnOverlay(OverlayID overlayID, const PointerEvent& event); void mousePressOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Triggered when a mouse double press event occurs on an overlay. Only occurs for 3D overlays. * Triggered when a mouse double press event occurs on an overlay. Only occurs for 3D overlays.
* @function Overlays.mouseDoublePressOnOverlay * @function Overlays.mouseDoublePressOnOverlay
* @param {Uuid} overlayID - The ID of the overlay the mouse double press event occurred on. * @param {Uuid} id - The ID of the overlay the mouse double press event occurred on.
* @param {PointerEvent} event - The mouse double press event details. * @param {PointerEvent} event - The mouse double press event details.
* @returns {Signal} * @returns {Signal}
*/ */
void mouseDoublePressOnOverlay(OverlayID overlayID, const PointerEvent& event); void mouseDoublePressOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Triggered when a mouse release event occurs on an overlay. Only occurs for 3D overlays (unless you use * Triggered when a mouse release event occurs on an overlay. Only occurs for 3D overlays (unless you use
* {@link Overlays.sendMouseReleaseOnOverlay|sendMouseReleaseOnOverlay} for a 2D overlay). * {@link Overlays.sendMouseReleaseOnOverlay|sendMouseReleaseOnOverlay} for a 2D overlay).
* @function Overlays.mouseReleaseOnOverlay * @function Overlays.mouseReleaseOnOverlay
* @param {Uuid} overlayID - The ID of the overlay the mouse release event occurred on. * @param {Uuid} id - The ID of the overlay the mouse release event occurred on.
* @param {PointerEvent} event - The mouse release event details. * @param {PointerEvent} event - The mouse release event details.
* @returns {Signal} * @returns {Signal}
*/ */
void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event); void mouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Triggered when a mouse move event occurs on an overlay. Only occurs for 3D overlays (unless you use * Triggered when a mouse move event occurs on an overlay. Only occurs for 3D overlays (unless you use
* {@link Overlays.sendMouseMoveOnOverlay|sendMouseMoveOnOverlay} for a 2D overlay). * {@link Overlays.sendMouseMoveOnOverlay|sendMouseMoveOnOverlay} for a 2D overlay).
* @function Overlays.mouseMoveOnOverlay * @function Overlays.mouseMoveOnOverlay
* @param {Uuid} overlayID - The ID of the overlay the mouse moved event occurred on. * @param {Uuid} id - The ID of the overlay the mouse moved event occurred on.
* @param {PointerEvent} event - The mouse move event details. * @param {PointerEvent} event - The mouse move event details.
* @returns {Signal} * @returns {Signal}
*/ */
void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event); void mouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Triggered when a mouse press event occurs on something other than a 3D overlay. * Triggered when a mouse press event occurs on something other than a 3D overlay.
@ -675,7 +662,7 @@ signals:
* Triggered when a mouse cursor starts hovering over an overlay. Only occurs for 3D overlays (unless you use * Triggered when a mouse cursor starts hovering over an overlay. Only occurs for 3D overlays (unless you use
* {@link Overlays.sendHoverEnterOverlay|sendHoverEnterOverlay} for a 2D overlay). * {@link Overlays.sendHoverEnterOverlay|sendHoverEnterOverlay} for a 2D overlay).
* @function Overlays.hoverEnterOverlay * @function Overlays.hoverEnterOverlay
* @param {Uuid} overlayID - The ID of the overlay the mouse moved event occurred on. * @param {Uuid} id - The ID of the overlay the mouse moved event occurred on.
* @param {PointerEvent} event - The mouse move event details. * @param {PointerEvent} event - The mouse move event details.
* @returns {Signal} * @returns {Signal}
* @example <caption>Create a cube overlay in front of your avatar and report when you start hovering your mouse over * @example <caption>Create a cube overlay in front of your avatar and report when you start hovering your mouse over
@ -691,54 +678,53 @@ signals:
* print("Hover enter: " + overlayID); * print("Hover enter: " + overlayID);
* }); * });
*/ */
void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event); void hoverEnterOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Triggered when a mouse cursor continues hovering over an overlay. Only occurs for 3D overlays (unless you use * Triggered when a mouse cursor continues hovering over an overlay. Only occurs for 3D overlays (unless you use
* {@link Overlays.sendHoverOverOverlay|sendHoverOverOverlay} for a 2D overlay). * {@link Overlays.sendHoverOverOverlay|sendHoverOverOverlay} for a 2D overlay).
* @function Overlays.hoverOverOverlay * @function Overlays.hoverOverOverlay
* @param {Uuid} overlayID - The ID of the overlay the hover over event occurred on. * @param {Uuid} id - The ID of the overlay the hover over event occurred on.
* @param {PointerEvent} event - The hover over event details. * @param {PointerEvent} event - The hover over event details.
* @returns {Signal} * @returns {Signal}
*/ */
void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event); void hoverOverOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc /**jsdoc
* Triggered when a mouse cursor finishes hovering over an overlay. Only occurs for 3D overlays (unless you use * Triggered when a mouse cursor finishes hovering over an overlay. Only occurs for 3D overlays (unless you use
* {@link Overlays.sendHoverLeaveOverlay|sendHoverLeaveOverlay} for a 2D overlay). * {@link Overlays.sendHoverLeaveOverlay|sendHoverLeaveOverlay} for a 2D overlay).
* @function Overlays.hoverLeaveOverlay * @function Overlays.hoverLeaveOverlay
* @param {Uuid} overlayID - The ID of the overlay the hover leave event occurred on. * @param {Uuid} id - The ID of the overlay the hover leave event occurred on.
* @param {PointerEvent} event - The hover leave event details. * @param {PointerEvent} event - The hover leave event details.
* @returns {Signal} * @returns {Signal}
*/ */
void hoverLeaveOverlay(OverlayID overlayID, const PointerEvent& event); void hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
private: private:
void cleanupOverlaysToDelete(); void cleanupOverlaysToDelete();
mutable QMutex _mutex { QMutex::Recursive }; mutable QMutex _mutex { QMutex::Recursive };
QMap<OverlayID, Overlay::Pointer> _overlaysHUD; QMap<QUuid, Overlay::Pointer> _overlays;
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
QList<Overlay::Pointer> _overlaysToDelete; QList<Overlay::Pointer> _overlaysToDelete;
unsigned int _stackOrder { 1 }; unsigned int _stackOrder { 1 };
bool _enabled = true; bool _enabled { true };
std::atomic<bool> _shuttingDown{ false }; std::atomic<bool> _shuttingDown { false };
PointerEvent calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, RayToOverlayIntersectionResult rayPickResult, PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
QMouseEvent* event, PointerEvent::EventType eventType); QMouseEvent* event, PointerEvent::EventType eventType);
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID }; QUuid _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID }; QUuid _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
private slots: private slots:
void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mousePressPointerEvent(const QUuid& id, const PointerEvent& event);
void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event);
void mouseReleasePointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event);
void hoverEnterPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event);
void hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void hoverOverPointerEvent(const QUuid& id, const PointerEvent& event);
void hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event); void hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event);
}; };
#endif // hifi_Overlays_h #endif // hifi_Overlays_h

View file

@ -104,8 +104,8 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
}); });
_emitting = entity->getIsEmitting(); _emitting = entity->getIsEmitting();
bool hasTexture = resultWithReadLock<bool>([&]{ return _particleProperties.textures.isEmpty(); }); bool textureEmpty = resultWithReadLock<bool>([&]{ return _particleProperties.textures.isEmpty(); });
if (hasTexture) { if (textureEmpty) {
if (_networkTexture) { if (_networkTexture) {
withWriteLock([&] { withWriteLock([&] {
_networkTexture.reset(); _networkTexture.reset();

View file

@ -23,6 +23,9 @@ using namespace render;
using namespace render::entities; using namespace render::entities;
static const int FIXED_FONT_POINT_SIZE = 40; static const int FIXED_FONT_POINT_SIZE = 40;
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 92.0f; // Determined through experimentation to fit font to line
// height.
const float LINE_SCALE_RATIO = 1.2f;
TextEntityRenderer::TextEntityRenderer(const EntityItemPointer& entity) : TextEntityRenderer::TextEntityRenderer(const EntityItemPointer& entity) :
Parent(entity), Parent(entity),
@ -205,3 +208,12 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
dimensions.y - (_topMargin + _bottomMargin)); dimensions.y - (_topMargin + _bottomMargin));
_textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale); _textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale);
} }
QSizeF TextEntityRenderer::textSize(const QString& text) const {
auto extents = _textRenderer->computeExtent(text);
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
return QSizeF(extents.x, extents.y) * pointToWorldScale;
}

View file

@ -29,6 +29,8 @@ public:
bool isTransparent() const override; bool isTransparent() const override;
ShapeKey getShapeKey() override; ShapeKey getShapeKey() override;
QSizeF textSize(const QString& text) const;
private: private:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;

View file

@ -47,6 +47,9 @@ public:
} }
} }
virtual void setProxyWindow(QWindow* proxyWindow) override;
virtual QObject* getEventHandler() override;
protected: protected:
virtual bool needsRenderUpdate() const override; virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
@ -57,9 +60,6 @@ protected:
virtual bool wantsHandControllerPointerEvents() const override { return true; } virtual bool wantsHandControllerPointerEvents() const override { return true; }
virtual bool wantsKeyboardFocus() const override { return true; } virtual bool wantsKeyboardFocus() const override { return true; }
virtual void setProxyWindow(QWindow* proxyWindow) override;
virtual QObject* getEventHandler() override;
void handlePointerEventAsTouch(const PointerEvent& event); void handlePointerEventAsTouch(const PointerEvent& event);
void handlePointerEventAsMouse(const PointerEvent& event); void handlePointerEventAsMouse(const PointerEvent& event);

View file

@ -571,7 +571,7 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin
return addEntity(properties); return addEntity(properties);
} }
QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { QUuid EntityScriptingInterface::cloneEntity(const QUuid& entityIDToClone) {
EntityItemID newEntityID; EntityItemID newEntityID;
EntityItemProperties properties = getEntityProperties(entityIDToClone); EntityItemProperties properties = getEntityProperties(entityIDToClone);
bool cloneAvatarEntity = properties.getCloneAvatarEntity(); bool cloneAvatarEntity = properties.getCloneAvatarEntity();
@ -596,12 +596,12 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) {
} }
} }
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID) { EntityItemProperties EntityScriptingInterface::getEntityProperties(const QUuid& entityID) {
const EntityPropertyFlags noSpecificProperties; const EntityPropertyFlags noSpecificProperties;
return getEntityProperties(entityID, noSpecificProperties); return getEntityProperties(entityID, noSpecificProperties);
} }
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties) { EntityItemProperties EntityScriptingInterface::getEntityProperties(const QUuid& entityID, EntityPropertyFlags desiredProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
bool scalesWithParent { false }; bool scalesWithParent { false };
@ -775,7 +775,7 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri
return finalResult; return finalResult;
} }
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) { QUuid EntityScriptingInterface::editEntity(const QUuid& id, const EntityItemProperties& scriptSideProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
_activityTracking.editedEntityCount++; _activityTracking.editedEntityCount++;
@ -960,7 +960,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
return id; return id;
} }
void EntityScriptingInterface::deleteEntity(QUuid id) { void EntityScriptingInterface::deleteEntity(const QUuid& id) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
_activityTracking.deletedEntityCount++; _activityTracking.deletedEntityCount++;
@ -1005,12 +1005,49 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
} }
} }
QString EntityScriptingInterface::getEntityType(const QUuid& entityID) {
QString toReturn;
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
toReturn = EntityTypes::getEntityTypeName(entity->getType());
}
});
return toReturn;
}
QObject* EntityScriptingInterface::getEntityObject(const QUuid& id) {
QObject* toReturn { nullptr };
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(id);
if (entity) {
toReturn = qobject_cast<QObject*>(&(*entity));
}
});
return toReturn;
}
bool EntityScriptingInterface::isLoaded(const QUuid& id) {
bool toReturn = false;
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(id);
if (entity) {
toReturn = entity->isVisuallyReady();
}
});
return toReturn;
}
QSizeF EntityScriptingInterface::textSize(const QUuid& id, const QString& text) {
return EntityTree::textSize(id, text);
}
void EntityScriptingInterface::setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine) { void EntityScriptingInterface::setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine) {
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock); std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
_entitiesScriptEngine = engine; _entitiesScriptEngine = engine;
} }
void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method, const QStringList& params) { void EntityScriptingInterface::callEntityMethod(const QUuid& id, const QString& method, const QStringList& params) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock); std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
@ -1020,12 +1057,12 @@ void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method,
} }
} }
void EntityScriptingInterface::callEntityServerMethod(QUuid id, const QString& method, const QStringList& params) { void EntityScriptingInterface::callEntityServerMethod(const QUuid& id, const QString& method, const QStringList& params) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
DependencyManager::get<EntityScriptClient>()->callEntityServerMethod(id, method, params); DependencyManager::get<EntityScriptClient>()->callEntityServerMethod(id, method, params);
} }
void EntityScriptingInterface::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) { void EntityScriptingInterface::callEntityClientMethod(const QUuid& clientSessionID, const QUuid& entityID, const QString& method, const QStringList& params) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
auto scriptServerServices = DependencyManager::get<EntityScriptServerServices>(); auto scriptServerServices = DependencyManager::get<EntityScriptServerServices>();
@ -1262,7 +1299,7 @@ ParabolaToEntityIntersectionResult EntityScriptingInterface::evalParabolaInterse
return result; return result;
} }
bool EntityScriptingInterface::reloadServerScripts(QUuid entityID) { bool EntityScriptingInterface::reloadServerScripts(const QUuid& entityID) {
auto client = DependencyManager::get<EntityScriptClient>(); auto client = DependencyManager::get<EntityScriptClient>();
return client->reloadServerScript(entityID); return client->reloadServerScript(entityID);
} }
@ -1335,7 +1372,7 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScript
return true; return true;
} }
bool EntityScriptingInterface::queryPropertyMetadata(QUuid entityID, QScriptValue property, QScriptValue scopeOrCallback, QScriptValue methodOrName) { bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, QScriptValue property, QScriptValue scopeOrCallback, QScriptValue methodOrName) {
auto name = property.toString(); auto name = property.toString();
auto handler = makeScopedHandlerObject(scopeOrCallback, methodOrName); auto handler = makeScopedHandlerObject(scopeOrCallback, methodOrName);
QPointer<BaseScriptEngine> engine = dynamic_cast<BaseScriptEngine*>(handler.engine()); QPointer<BaseScriptEngine> engine = dynamic_cast<BaseScriptEngine*>(handler.engine());
@ -1379,7 +1416,7 @@ bool EntityScriptingInterface::queryPropertyMetadata(QUuid entityID, QScriptValu
} }
} }
bool EntityScriptingInterface::getServerScriptStatus(QUuid entityID, QScriptValue callback) { bool EntityScriptingInterface::getServerScriptStatus(const QUuid& entityID, QScriptValue callback) {
auto client = DependencyManager::get<EntityScriptClient>(); auto client = DependencyManager::get<EntityScriptClient>();
auto request = client->createScriptStatusRequest(entityID); auto request = client->createScriptStatusRequest(entityID);
connect(request, &GetScriptStatusRequest::finished, callback.engine(), [callback](GetScriptStatusRequest* request) mutable { connect(request, &GetScriptStatusRequest::finished, callback.engine(), [callback](GetScriptStatusRequest* request) mutable {
@ -1518,14 +1555,14 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(Line
return success; return success;
} }
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { bool EntityScriptingInterface::setVoxelSphere(const QUuid& entityID, const glm::vec3& center, float radius, int value) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
return polyVoxWorker(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
return polyVoxEntity.setSphere(center, radius, value); return polyVoxEntity.setSphere(center, radius, value);
}); });
} }
bool EntityScriptingInterface::setVoxelCapsule(QUuid entityID, bool EntityScriptingInterface::setVoxelCapsule(const QUuid& entityID,
const glm::vec3& start, const glm::vec3& end, const glm::vec3& start, const glm::vec3& end,
float radius, int value) { float radius, int value) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
@ -1535,7 +1572,7 @@ bool EntityScriptingInterface::setVoxelCapsule(QUuid entityID,
}); });
} }
bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { bool EntityScriptingInterface::setVoxel(const QUuid& entityID, const glm::vec3& position, int value) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
return polyVoxWorker(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) {
@ -1543,7 +1580,7 @@ bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& positio
}); });
} }
bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { bool EntityScriptingInterface::setAllVoxels(const QUuid& entityID, int value) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
return polyVoxWorker(entityID, [value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [value](PolyVoxEntityItem& polyVoxEntity) {
@ -1551,7 +1588,7 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
}); });
} }
bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, bool EntityScriptingInterface::setVoxelsInCuboid(const QUuid& entityID, const glm::vec3& lowPosition,
const glm::vec3& cuboidSize, int value) { const glm::vec3& cuboidSize, int value) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
@ -1560,7 +1597,7 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3
}); });
} }
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) { bool EntityScriptingInterface::setAllPoints(const QUuid& entityID, const QVector<glm::vec3>& points) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID)); EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
@ -1580,7 +1617,7 @@ bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::v
return false; return false;
} }
bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& point) { bool EntityScriptingInterface::appendPoint(const QUuid& entityID, const glm::vec3& point) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID)); EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
@ -2040,7 +2077,7 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
return result; return result;
} }
bool EntityScriptingInterface::isChildOfParent(QUuid childID, QUuid parentID) { bool EntityScriptingInterface::isChildOfParent(const QUuid& childID, const QUuid& parentID) {
bool isChild = false; bool isChild = false;
if (!_entityTree) { if (!_entityTree) {
@ -2062,7 +2099,7 @@ bool EntityScriptingInterface::isChildOfParent(QUuid childID, QUuid parentID) {
return isChild; return isChild;
} }
QString EntityScriptingInterface::getNestableType(QUuid id) { QString EntityScriptingInterface::getNestableType(const QUuid& id) {
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>(); QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) { if (!parentFinder) {
return "unknown"; return "unknown";
@ -2164,7 +2201,7 @@ void EntityScriptingInterface::sendHoverLeaveEntity(const EntityItemID& id, cons
emit hoverLeaveEntity(id, event); emit hoverLeaveEntity(id, event);
} }
bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) { bool EntityScriptingInterface::wantsHandControllerPointerEvents(const QUuid& id) {
bool result = false; bool result = false;
if (_entityTree) { if (_entityTree) {
_entityTree->withReadLock([&] { _entityTree->withReadLock([&] {
@ -2196,7 +2233,7 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons
return aaBox.findCapsulePenetration(start, end, radius, penetration); return aaBox.findCapsulePenetration(start, end, radius, penetration);
} }
void EntityScriptingInterface::getMeshes(QUuid entityID, QScriptValue callback) { void EntityScriptingInterface::getMeshes(const QUuid& entityID, QScriptValue callback) {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID)); EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));

View file

@ -296,7 +296,7 @@ public slots:
* @param {Uuid} entityID - The ID of the entity to clone. * @param {Uuid} entityID - The ID of the entity to clone.
* @returns {Uuid} The ID of the new entity if successfully cloned, otherwise {@link Uuid|Uuid.NULL}. * @returns {Uuid} The ID of the new entity if successfully cloned, otherwise {@link Uuid|Uuid.NULL}.
*/ */
Q_INVOKABLE QUuid cloneEntity(QUuid entityIDToClone); Q_INVOKABLE QUuid cloneEntity(const QUuid& entityID);
/**jsdoc /**jsdoc
* Get the properties of an entity. * Get the properties of an entity.
@ -315,8 +315,8 @@ public slots:
* var properties = Entities.getEntityProperties(entityID, ["color"]); * var properties = Entities.getEntityProperties(entityID, ["color"]);
* print("Entity color: " + JSON.stringify(properties.color)); * print("Entity color: " + JSON.stringify(properties.color));
*/ */
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID); Q_INVOKABLE EntityItemProperties getEntityProperties(const QUuid& entityID);
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties); Q_INVOKABLE EntityItemProperties getEntityProperties(const QUuid& entityID, EntityPropertyFlags desiredProperties);
/**jsdoc /**jsdoc
* Update an entity with specified properties. * Update an entity with specified properties.
@ -340,7 +340,7 @@ public slots:
* properties = Entities.getEntityProperties(entityID, ["color"]); * properties = Entities.getEntityProperties(entityID, ["color"]);
* print("Entity color: " + JSON.stringify(properties.color)); * print("Entity color: " + JSON.stringify(properties.color));
*/ */
Q_INVOKABLE QUuid editEntity(QUuid entityID, const EntityItemProperties& properties); Q_INVOKABLE QUuid editEntity(const QUuid& entityID, const EntityItemProperties& properties);
/**jsdoc /**jsdoc
* Delete an entity. * Delete an entity.
@ -358,8 +358,50 @@ public slots:
* Entities.deleteEntity(entityID); * Entities.deleteEntity(entityID);
* }, 3000); * }, 3000);
*/ */
Q_INVOKABLE void deleteEntity(QUuid entityID); Q_INVOKABLE void deleteEntity(const QUuid& entityID);
/**jsdoc
* Get an entities type as a string.
* @function Entities.deleteEntity
* @param {Uuid} id - The id of the entity to get the type of.
*/
Q_INVOKABLE QString getEntityType(const QUuid& entityID);
/**jsdoc
* Get the entity script object. In particular, this is useful for accessing the event bridge for a <code>Web</code>
* entity.
* @function Entities.getEntityObject
* @param {Uuid} id - The ID of the entity to get the script object of.
* @returns {object} The script object for the entity if found.
*/
Q_INVOKABLE QObject* getEntityObject(const QUuid& id);
/**jsdoc
* Check whether an entities's assets have been loaded. For example, for an <code>Model</code> entity the result indicates
* whether its textures have been loaded.
* @function Entities.isLoaded
* @param {Uuid} id - The ID of the entity to check.
* @returns {boolean} <code>true</code> if the entity's assets have been loaded, otherwise <code>false</code>.
*/
Q_INVOKABLE bool isLoaded(const QUuid& id);
/**jsdoc
* Check if there is an object of a given ID.
* @function Entities.isAddedEntity
* @param {Uuid} id - The ID to check.
* @returns {boolean} <code>true</code> if an object with the given ID exists, <code>false</code> otherwise.
*/
Q_INVOKABLE bool isAddedEntity(const QUuid& id);
/**jsdoc
* Calculates the size of the given text in the specified object if it is a text entity.
* @function Entities.textSize
* @param {Uuid} id - The ID of the entity to use for calculation.
* @param {string} text - The string to calculate the size of.
* @returns {Size} The size of the <code>text</code> in meters if the object is a text entity, otherwise
* <code>{ height: 0, width : 0 }</code>.
*/
Q_INVOKABLE QSizeF textSize(const QUuid& id, const QString& text);
/**jsdoc /**jsdoc
* Call a method in a client entity script from a client script or client entity script, or call a method in a server * Call a method in a client entity script from a client script or client entity script, or call a method in a server
@ -371,7 +413,7 @@ public slots:
* @param {string} method - The name of the method to call. * @param {string} method - The name of the method to call.
* @param {string[]} [parameters=[]] - The parameters to call the specified method with. * @param {string[]} [parameters=[]] - The parameters to call the specified method with.
*/ */
Q_INVOKABLE void callEntityMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList()); Q_INVOKABLE void callEntityMethod(const QUuid& entityID, const QString& method, const QStringList& params = QStringList());
/**jsdoc /**jsdoc
* Call a method in a server entity script from a client script or client entity script. The entity script method must be * Call a method in a server entity script from a client script or client entity script. The entity script method must be
@ -383,7 +425,7 @@ public slots:
* @param {string} method - The name of the method to call. * @param {string} method - The name of the method to call.
* @param {string[]} [parameters=[]] - The parameters to call the specified method with. * @param {string[]} [parameters=[]] - The parameters to call the specified method with.
*/ */
Q_INVOKABLE void callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList()); Q_INVOKABLE void callEntityServerMethod(const QUuid& entityID, const QString& method, const QStringList& params = QStringList());
/**jsdoc /**jsdoc
* Call a method in a specific user's client entity script from a server entity script. The entity script method must be * Call a method in a specific user's client entity script from a server entity script. The entity script method must be
@ -394,7 +436,7 @@ public slots:
* @param {string} method - The name of the method to call. * @param {string} method - The name of the method to call.
* @param {string[]} [parameters=[]] - The parameters to call the specified method with. * @param {string[]} [parameters=[]] - The parameters to call the specified method with.
*/ */
Q_INVOKABLE void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, Q_INVOKABLE void callEntityClientMethod(const QUuid& clientSessionID, const QUuid& entityID, const QString& method,
const QStringList& params = QStringList()); const QStringList& params = QStringList());
/**jsdoc /**jsdoc
@ -524,7 +566,7 @@ public slots:
* @returns {boolean} <code>true</code> if the reload request was successfully sent to the server, otherwise * @returns {boolean} <code>true</code> if the reload request was successfully sent to the server, otherwise
* <code>false</code>. * <code>false</code>.
*/ */
Q_INVOKABLE bool reloadServerScripts(QUuid entityID); Q_INVOKABLE bool reloadServerScripts(const QUuid& entityID);
/**jsdoc /**jsdoc
* Gets the status of server entity script attached to an entity * Gets the status of server entity script attached to an entity
@ -543,7 +585,7 @@ public slots:
* @param {string} errorInfo - <code>""</code> if there is a server entity script running, otherwise it may contain extra * @param {string} errorInfo - <code>""</code> if there is a server entity script running, otherwise it may contain extra
* information on the error. * information on the error.
*/ */
Q_INVOKABLE bool getServerScriptStatus(QUuid entityID, QScriptValue callback); Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, QScriptValue callback);
/**jsdoc /**jsdoc
* Get metadata for certain entity properties such as <code>script</code> and <code>serverScripts</code>. * Get metadata for certain entity properties such as <code>script</code> and <code>serverScripts</code>.
@ -573,7 +615,7 @@ public slots:
* @param {object} result - The metadata for the requested entity property if there was no error, otherwise * @param {object} result - The metadata for the requested entity property if there was no error, otherwise
* <code>undefined</code>. * <code>undefined</code>.
*/ */
Q_INVOKABLE bool queryPropertyMetadata(QUuid entityID, QScriptValue property, QScriptValue scopeOrCallback, Q_INVOKABLE bool queryPropertyMetadata(const QUuid& entityID, QScriptValue property, QScriptValue scopeOrCallback,
QScriptValue methodOrName = QScriptValue()); QScriptValue methodOrName = QScriptValue());
@ -657,7 +699,7 @@ public slots:
* Entities.setVoxelSphere(polyVox, position, 0.9, 255); * Entities.setVoxelSphere(polyVox, position, 0.9, 255);
*/ */
// FIXME move to a renderable entity interface // FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); Q_INVOKABLE bool setVoxelSphere(const QUuid& entityID, const glm::vec3& center, float radius, int value);
/**jsdoc /**jsdoc
* Set the values of all voxels in a capsule-shaped portion of a {@link Entities.EntityType|PolyVox} entity. * Set the values of all voxels in a capsule-shaped portion of a {@link Entities.EntityType|PolyVox} entity.
@ -681,7 +723,7 @@ public slots:
* Entities.setVoxelCapsule(polyVox, startPosition, endPosition, 0.5, 255); * Entities.setVoxelCapsule(polyVox, startPosition, endPosition, 0.5, 255);
*/ */
// FIXME move to a renderable entity interface // FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxelCapsule(QUuid entityID, const glm::vec3& start, const glm::vec3& end, float radius, int value); Q_INVOKABLE bool setVoxelCapsule(const QUuid& entityID, const glm::vec3& start, const glm::vec3& end, float radius, int value);
/**jsdoc /**jsdoc
* Set the value of a particular voxels in a {@link Entities.EntityType|PolyVox} entity. * Set the value of a particular voxels in a {@link Entities.EntityType|PolyVox} entity.
@ -703,7 +745,7 @@ public slots:
* Entities.setVoxel(entity, { x: 0, y: 0, z: 0 }, 0); * Entities.setVoxel(entity, { x: 0, y: 0, z: 0 }, 0);
*/ */
// FIXME move to a renderable entity interface // FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); Q_INVOKABLE bool setVoxel(const QUuid& entityID, const glm::vec3& position, int value);
/**jsdoc /**jsdoc
* Set the values of all voxels in a {@link Entities.EntityType|PolyVox} entity. * Set the values of all voxels in a {@link Entities.EntityType|PolyVox} entity.
@ -721,7 +763,7 @@ public slots:
* Entities.setAllVoxels(entity, 1); * Entities.setAllVoxels(entity, 1);
*/ */
// FIXME move to a renderable entity interface // FIXME move to a renderable entity interface
Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE bool setAllVoxels(const QUuid& entityID, int value);
/**jsdoc /**jsdoc
* Set the values of all voxels in a cubic portion of a {@link Entities.EntityType|PolyVox} entity. * Set the values of all voxels in a cubic portion of a {@link Entities.EntityType|PolyVox} entity.
@ -746,7 +788,7 @@ public slots:
* Entities.setVoxelsInCuboid(polyVox, cuboidPosition, cuboidSize, 0); * Entities.setVoxelsInCuboid(polyVox, cuboidPosition, cuboidSize, 0);
*/ */
// FIXME move to a renderable entity interface // FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value); Q_INVOKABLE bool setVoxelsInCuboid(const QUuid& entityID, const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value);
/**jsdoc /**jsdoc
* Convert voxel coordinates in a {@link Entities.EntityType|PolyVox} entity to world coordinates. Voxel coordinates are * Convert voxel coordinates in a {@link Entities.EntityType|PolyVox} entity to world coordinates. Voxel coordinates are
@ -862,7 +904,7 @@ public slots:
* ]); * ]);
* }, 2000); * }, 2000);
*/ */
Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points); Q_INVOKABLE bool setAllPoints(const QUuid& entityID, const QVector<glm::vec3>& points);
/**jsdoc /**jsdoc
* Append a point to a {@link Entities.EntityType|Line} entity. * Append a point to a {@link Entities.EntityType|Line} entity.
@ -890,7 +932,7 @@ public slots:
* // Add a third point to create a "V". * // Add a third point to create a "V".
* Entities.appendPoint(entity, { x: 1, y: 1, z: 0 }); * Entities.appendPoint(entity, { x: 1, y: 1, z: 0 });
*/ */
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point); Q_INVOKABLE bool appendPoint(const QUuid& entityID, const glm::vec3& point);
/**jsdoc /**jsdoc
* Dumps debug information about all entities in Interface's local in-memory tree of entities it knows about to the program log. * Dumps debug information about all entities in Interface's local in-memory tree of entities it knows about to the program log.
@ -1355,7 +1397,7 @@ public slots:
* *
* print("grandChild has root as parent: " + Entities.isChildOfParent(grandChild, root)); // true * print("grandChild has root as parent: " + Entities.isChildOfParent(grandChild, root)); // true
*/ */
Q_INVOKABLE bool isChildOfParent(QUuid childID, QUuid parentID); Q_INVOKABLE bool isChildOfParent(const QUuid& childID, const QUuid& parentID);
/**jsdoc /**jsdoc
* Get the type &mdash; entity, overlay, or avatar &mdash; of an in-world item. * Get the type &mdash; entity, overlay, or avatar &mdash; of an in-world item.
@ -1374,7 +1416,7 @@ public slots:
* print(Entities.getNestableType(entity)); // "entity" * print(Entities.getNestableType(entity)); // "entity"
* print(Entities.getNestableType(Uuid.generate())); // "unknown" * print(Entities.getNestableType(Uuid.generate())); // "unknown"
*/ */
Q_INVOKABLE QString getNestableType(QUuid entityID); Q_INVOKABLE QString getNestableType(const QUuid& entityID);
/**jsdoc /**jsdoc
* Get the ID of the {@link Entities.EntityType|Web} entity that has keyboard focus. * Get the ID of the {@link Entities.EntityType|Web} entity that has keyboard focus.
@ -1486,7 +1528,7 @@ public slots:
* @returns {boolean} <code>true</code> if the entity can be found and it wants hand controller pointer events, otherwise * @returns {boolean} <code>true</code> if the entity can be found and it wants hand controller pointer events, otherwise
* <code>false</code>. * <code>false</code>.
*/ */
Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id); Q_INVOKABLE bool wantsHandControllerPointerEvents(const QUuid& id);
/**jsdoc /**jsdoc
* Send a script event over a {@link Entities.EntityType|Web} entity's <code>EventBridge</code> to the Web page's scripts. * Send a script event over a {@link Entities.EntityType|Web} entity's <code>EventBridge</code> to the Web page's scripts.
@ -1527,7 +1569,7 @@ public slots:
* @deprecated Use the {@link Graphics} API instead. * @deprecated Use the {@link Graphics} API instead.
*/ */
// FIXME move to a renderable entity interface // FIXME move to a renderable entity interface
Q_INVOKABLE void getMeshes(QUuid entityID, QScriptValue callback); Q_INVOKABLE void getMeshes(const QUuid& entityID, QScriptValue callback);
/**jsdoc /**jsdoc
* Get the object to world transform, excluding scale, of an entity. * Get the object to world transform, excluding scale, of an entity.

View file

@ -2957,8 +2957,7 @@ std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> E
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromEntityOperator = nullptr; std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromEntityOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToAvatarOperator = nullptr; std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToAvatarOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromAvatarOperator = nullptr; std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromAvatarOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToOverlayOperator = nullptr; std::function<QSizeF(const QUuid&, const QString&)> EntityTree::_textSizeOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromOverlayOperator = nullptr;
bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
if (_addMaterialToEntityOperator) { if (_addMaterialToEntityOperator) {
@ -2988,18 +2987,11 @@ bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::Mater
return false; return false;
} }
bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { QSizeF EntityTree::textSize(const QUuid& id, const QString& text) {
if (_addMaterialToOverlayOperator) { if (_textSizeOperator) {
return _addMaterialToOverlayOperator(overlayID, material, parentMaterialName); return _textSizeOperator(id, text);
} }
return false; return QSizeF(0.0f, 0.0f);
}
bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
if (_removeMaterialFromOverlayOperator) {
return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialName);
}
return false;
} }
void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,

View file

@ -272,10 +272,8 @@ public:
static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName); static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName); static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
static void setAddMaterialToOverlayOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } static void setTextSizeOperator(std::function<QSizeF(const QUuid&, const QString&)> textSizeOperator) { _textSizeOperator = textSizeOperator; }
static void setRemoveMaterialFromOverlayOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } static QSizeF textSize(const QUuid& id, const QString& text);
static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName);
static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName);
std::map<QString, QString> getNamedPaths() const { return _namedPaths; } std::map<QString, QString> getNamedPaths() const { return _namedPaths; }
@ -389,8 +387,7 @@ private:
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator; static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator; static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator; static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToOverlayOperator; static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromOverlayOperator;
std::vector<int32_t> _staleProxies; std::vector<int32_t> _staleProxies;