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

View file

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

View file

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

View file

@ -54,18 +54,13 @@ Overlays::Overlays() {
void Overlays::cleanupAllOverlays() {
_shuttingDown = true;
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
QMap<QUuid, Overlay::Pointer> overlays;
{
QMutexLocker locker(&_mutex);
overlaysHUD.swap(_overlaysHUD);
overlaysWorld.swap(_overlaysWorld);
overlays.swap(_overlays);
}
foreach(Overlay::Pointer overlay, overlaysHUD) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, overlaysWorld) {
foreach(Overlay::Pointer overlay, overlays) {
_overlaysToDelete.push_back(overlay);
}
cleanupOverlaysToDelete();
@ -77,10 +72,7 @@ void Overlays::init() {
void Overlays::update(float deltatime) {
{
QMutexLocker locker(&_mutex);
foreach(const auto& thisOverlay, _overlaysHUD) {
thisOverlay->update(deltatime);
}
foreach(const auto& thisOverlay, _overlaysWorld) {
foreach(const auto& thisOverlay, _overlays) {
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__);
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);
QMutexLocker locker(&_mutex);
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
foreach(Overlay::Pointer thisOverlay, _overlays) {
// Reset all batch pipeline settings between overlay
geometryCache->useSimpleDrawPipeline(batch);
@ -146,29 +138,28 @@ void Overlays::enable() {
// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder
// class on packet processing threads
Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
Overlay::Pointer Overlays::get2DOverlay(const QUuid& id) const {
if (_shuttingDown) {
return nullptr;
}
QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) {
return _overlaysHUD[id];
} else if (_overlaysWorld.contains(id)) {
return _overlaysWorld[id];
auto overlayIter = _overlays.find(id);
if (overlayIter != _overlays.end()) {
return overlayIter.value();
}
return nullptr;
}
OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) {
QUuid Overlays::addOverlay(const QString& type, const QVariant& properties) {
if (_shuttingDown) {
return UNKNOWN_OVERLAY_ID;
}
if (QThread::currentThread() != thread()) {
OverlayID result;
QUuid result;
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;
}
@ -267,58 +258,69 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties)
if (thisOverlay) {
thisOverlay->setProperties(properties.toMap());
return addOverlay(thisOverlay);
return add2DOverlay(thisOverlay);
}
return UNKNOWN_OVERLAY_ID;
}
OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
QUuid Overlays::add2DOverlay(const Overlay::Pointer& overlay) {
if (_shuttingDown) {
return UNKNOWN_OVERLAY_ID;
}
OverlayID thisID = OverlayID(QUuid::createUuid());
QUuid thisID = QUuid::createUuid();
overlay->setOverlayID(thisID);
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);
_overlaysHUD[thisID] = overlay;
_overlays[thisID] = overlay;
}
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) {
return false;
}
auto thisOverlay = getOverlay(id);
if (!thisOverlay) {
return false;
}
auto overlay = get2DOverlay(id);
if (overlay) {
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()) {
// 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));
overlay->setProperties(properties.toMap());
return true;
}
thisOverlay->setProperties(properties.toMap());
return true;
EntityItemProperties entityProperties = convertOverlayToEntityProperties(properties.toMap());
return !DependencyManager::get<EntityScriptingInterface>()->editEntity(id, entityProperties).isNull();
}
bool Overlays::editOverlays(const QVariant& propertiesById) {
@ -326,165 +328,166 @@ bool Overlays::editOverlays(const QVariant& propertiesById) {
return false;
}
bool defer2DOverlays = QThread::currentThread() != thread();
bool deferOverlays = QThread::currentThread() != thread();
QVariantMap deferrred;
QVariantMap deferred;
const QVariantMap map = propertiesById.toMap();
bool success = true;
for (const auto& key : map.keys()) {
OverlayID id = OverlayID(key);
Overlay::Pointer thisOverlay = getOverlay(id);
if (!thisOverlay) {
success = false;
continue;
}
QUuid id = QUuid(key);
const QVariant& properties = map[key];
if (defer2DOverlays && !thisOverlay->is3D()) {
deferrred[key] = properties;
continue;
Overlay::Pointer overlay = get2DOverlay(id);
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
if (defer2DOverlays && !deferrred.empty()) {
if (!deferred.empty()) {
// 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) {
return;
}
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
_overlaysToDelete.push_back(overlay);
emit overlayDeleted(id);
return;
}
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(id);
emit overlayDeleted(id);
}
QString Overlays::getOverlayType(OverlayID overlayId) {
QString Overlays::getOverlayType(const QUuid& id) {
if (_shuttingDown) {
return "";
}
if (QThread::currentThread() != thread()) {
QString result;
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;
}
Overlay::Pointer overlay = getOverlay(overlayId);
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
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()) {
QObject* result;
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;
}
Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) {
return qobject_cast<QObject*>(&(*thisOverlay));
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
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) {
return UNKNOWN_OVERLAY_ID;
return UNKNOWN_ENTITY_ID;
}
QMutexLocker locker(&_mutex);
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
QMapIterator<QUuid, Overlay::Pointer> i(_overlays);
unsigned int bestStackOrder = 0;
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
QUuid bestID = UNKNOWN_ENTITY_ID;
while (i.hasNext()) {
i.next();
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
thisOverlay->getBoundingRect().contains(point.x, point.y, false)) {
if (thisOverlay->getStackOrder() > bestStackOrder) {
bestOverlayID = i.key();
bestID = i.key();
bestStackOrder = thisOverlay->getStackOrder();
}
}
}
return bestOverlayID;
return bestID;
}
OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) {
Overlay::Pointer thisOverlay = getOverlay(id);
OverlayPropertyResult result;
if (thisOverlay && thisOverlay->supportsGetProperty()) {
result.value = thisOverlay->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));
QVariant Overlays::getProperty(const QUuid& id, const QString& property) {
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
if (overlay->supportsGetProperty()) {
return overlay->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 map = propertiesById.toMap();
OverlayPropertyResult result;
QVariantMap resultMap;
for (const auto& key : map.keys()) {
OverlayID id = OverlayID(key);
QVariantMap overlayResult;
Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay && thisOverlay->supportsGetProperty()) {
QStringList propertiesToFetch = map[key].toStringList();
for (const auto& property : propertiesToFetch) {
overlayResult[property] = thisOverlay->getProperty(property);
QVariantMap Overlays::getProperties(const QUuid& id, const QStringList& properties) {
Overlay::Pointer overlay = get2DOverlay(id);
QVariantMap result;
if (overlay) {
if (overlay->supportsGetProperty()) {
for (const auto& property : properties) {
result.insert(property, overlay->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;
}
OverlayPropertyResult::OverlayPropertyResult() {
}
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value) {
if (!value.value.isValid()) {
return QScriptValue::UndefinedValue;
QVariantMap Overlays::getOverlaysProperties(const QVariant& propertiesById) {
QVariantMap map = propertiesById.toMap();
QVariantMap result;
for (const auto& key : map.keys()) {
result[key] = getProperties(QUuid(key), map[key].toStringList());
}
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,
const QScriptValue& overlayIDsToInclude,
const QScriptValue& overlayIDsToDiscard,
bool visibleOnly, bool collidableOnly) {
const QVector<OverlayID> overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude);
const QVector<OverlayID> overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard);
const QVector<QUuid> overlaysToInclude = qVectorQUuidFromScriptValue(overlayIDsToInclude);
const QVector<QUuid> overlaysToDiscard = qVectorQUuidFromScriptValue(overlayIDsToDiscard);
return findRayIntersectionVector(ray, precisionPicking,
overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly);
@ -492,8 +495,8 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray,
RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard,
const QVector<QUuid>& overlaysToInclude,
const QVector<QUuid>& overlaysToDiscard,
bool visibleOnly, bool collidableOnly) {
float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false;
@ -624,77 +627,71 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
value.extraInfo = object.property("extraInfo").toVariant().toMap();
}
bool Overlays::isLoaded(OverlayID id) {
bool Overlays::isLoaded(const QUuid& id) {
if (QThread::currentThread() != thread()) {
bool result;
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;
}
Overlay::Pointer thisOverlay = getOverlay(id);
if (!thisOverlay) {
return false; // not found
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
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()) {
QSizeF result;
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;
}
Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) {
if (thisOverlay->is3D()) {
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
return text3dOverlay->textSize(text);
}
} else {
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
return textOverlay->textSize(text);
}
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(overlay)) {
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) {
if (QThread::currentThread() != thread()) {
bool result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
return result;
bool Overlays::isAddedOverlay(const QUuid& id) {
Overlay::Pointer overlay = get2DOverlay(id);
if (overlay) {
return true;
}
QMutexLocker locker(&_mutex);
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
return DependencyManager::get<EntityScriptingInterface>()->isAddedEntity(id);
}
void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
void Overlays::sendMousePressOnOverlay(const QUuid& overlayID, const PointerEvent& 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);
}
void Overlays::sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
void Overlays::sendMouseMoveOnOverlay(const QUuid& overlayID, const PointerEvent& 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);
}
void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) {
void Overlays::sendHoverOverOverlay(const QUuid& overlayID, const PointerEvent& 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);
}
@ -765,10 +762,10 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
}
}
PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray,
RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event,
PointerEvent Overlays::calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray,
const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event,
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") {
overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
}
@ -793,8 +790,7 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mousePressEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<OverlayID>(),
QVector<OverlayID>());
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<QUuid>(), QVector<QUuid>());
if (rayPickResult.intersects) {
_currentClickingOnOverlayID = rayPickResult.overlayID;
@ -839,8 +835,7 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<OverlayID>(),
QVector<OverlayID>());
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector<OverlayID>(), QVector<OverlayID>());
if (rayPickResult.intersects) {
_currentClickingOnOverlayID = rayPickResult.overlayID;

View file

@ -32,19 +32,6 @@
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
* The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}.
* @typedef {object} Overlays.RayToOverlayIntersectionResult
@ -59,7 +46,7 @@ const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
class RayToOverlayIntersectionResult {
public:
bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
QUuid overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0.0f };
BoxFace face { UNKNOWN_FACE };
glm::vec3 surfaceNormal;
@ -73,7 +60,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
class ParabolaToOverlayIntersectionResult {
public:
bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
QUuid overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0.0f };
float parabolicDistance { 0.0f };
BoxFace face { UNKNOWN_FACE };
@ -83,7 +70,7 @@ public:
};
/**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.
* @namespace Overlays
*
@ -98,31 +85,31 @@ public:
class Overlays : public QObject {
Q_OBJECT
Q_PROPERTY(OverlayID keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay)
Q_PROPERTY(QUuid keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay)
public:
Overlays();
void init();
void update(float deltatime);
void renderHUD(RenderArgs* renderArgs);
void render(RenderArgs* renderArgs);
void disable();
void enable();
Overlay::Pointer getOverlay(OverlayID id) const;
Overlay::Pointer get2DOverlay(const QUuid& id) const;
/// adds an overlay that's already been created
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
OverlayID addOverlay(const Overlay::Pointer& overlay);
QUuid addOverlay(Overlay* overlay) { return add2DOverlay(Overlay::Pointer(overlay)); }
QUuid add2DOverlay(const Overlay::Pointer& overlay);
RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard,
const QVector<QUuid>& overlaysToInclude,
const QVector<QUuid>& overlaysToDiscard,
bool visibleOnly = false, bool collidableOnly = false);
ParabolaToOverlayIntersectionResult findParabolaIntersectionVector(const PickParabola& parabola, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard,
const QVector<QUuid>& overlaysToInclude,
const QVector<QUuid>& overlaysToDiscard,
bool visibleOnly = false, bool collidableOnly = false);
bool mousePressEvent(QMouseEvent* event);
@ -147,20 +134,20 @@ public slots:
* solid: true
* });
*/
OverlayID addOverlay(const QString& type, const QVariant& properties);
QUuid addOverlay(const QString& type, const QVariant& properties);
/**jsdoc
* Create a clone of an existing entity.
* Create a clone of an existing entity (or 2D overlay).
* @function Overlays.cloneOverlay
* @param {Uuid} id - The ID of the entity to clone.
* @returns {Uuid} The ID of the new entity if successful, otherwise {@link Uuid|Uuid.NULL}.
* @param {Uuid} id - The ID of the entity/2D overlay to clone.
* @returns {Uuid} The ID of the new object if successful, otherwise {@link Uuid|Uuid.NULL}.
*/
EntityItemID cloneOverlay(EntityItemID id) { return DependencyManager::get<EntityScriptingInterface>()->cloneEntity(id); }
QUuid cloneOverlay(const QUuid& id);
/**jsdoc
* Edit an overlay's properties.
* @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.
* @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>
@ -176,7 +163,7 @@ public slots:
* });
* print("Success: " + success);
*/
bool editOverlay(OverlayID id, const QVariant& properties);
bool editOverlay(const QUuid& id, const QVariant& properties);
/**jsdoc
* Edit multiple overlays' properties.
@ -208,18 +195,18 @@ public slots:
bool editOverlays(const QVariant& propertiesById);
/**jsdoc
* Delete an entity.
* Delete an entity or 2D overlay.
* @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
* Get the type of an overlay.
* Get the type of an entity or 2D overlay.
* @function Overlays.getOverlayType
* @param {Uuid} overlayID - The ID of the overlay to get the type of.
* @returns {Overlays.OverlayType} The type of the overlay if found, otherwise an empty string.
* @example <caption>Create an overlay in front of your avatar then get and report its type.</caption>
* @param {Uuid} id - The ID of the object to get the type of.
* @returns {string} The type of the object if found, otherwise an empty string.
* @example <caption>Create an object in front of your avatar then get and report its type.</caption>
* var overlay = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
* rotation: MyAvatar.orientation,
@ -229,7 +216,7 @@ public slots:
* var type = Overlays.getOverlayType(overlay);
* print("Type: " + type);
*/
QString getOverlayType(OverlayID overlayId);
QString getOverlayType(const QUuid& id);
/**jsdoc
* Get the overlay script object. In particular, this is useful for accessing the event bridge for a <code>web3d</code>
@ -273,7 +260,7 @@ public slots:
* Overlays.deleteOverlay(web3dOverlay);
* });
*/
QObject* getOverlayObject(OverlayID id);
QObject* getOverlayObject(const QUuid& id);
/**jsdoc
* 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);
* });
*/
OverlayID getOverlayAtPoint(const glm::vec2& point);
QUuid getOverlayAtPoint(const glm::vec2& point);
/**jsdoc
* Get the value of a 3D overlay's property.
* @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.
* @returns {object} The value of the property if the 3D overlay and property can be found, otherwise
* <code>undefined</code>.
@ -311,12 +298,12 @@ public slots:
* var alpha = Overlays.getProperty(overlay, "alpha");
* print("Overlay alpha: " + alpha);
*/
OverlayPropertyResult getProperty(OverlayID id, const QString& property);
QVariant getProperty(const QUuid& id, const QString& property);
/**jsdoc
* Get the values of an overlay's properties.
* @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.
* @returns {Overlays.OverlayProperties} The values of valid properties if the overlay can be found, otherwise
* <code>undefined</code>.
@ -330,7 +317,7 @@ public slots:
* var properties = Overlays.getProperties(overlay, ["color", "alpha", "grabbable"]);
* print("Overlay properties: " + JSON.stringify(properties));
*/
OverlayPropertyResult getProperties(const OverlayID& id, const QStringList& properties);
QVariantMap getProperties(const QUuid& id, const QStringList& properties);
/**jsdoc
* Get the values of multiple overlays' properties.
@ -358,7 +345,7 @@ public slots:
* var properties = Overlays.getOverlaysProperties(propertiesToGet);
* print("Overlays properties: " + JSON.stringify(properties));
*/
OverlayPropertyResult getOverlaysProperties(const QVariant& overlaysProperties);
QVariantMap getOverlaysProperties(const QVariant& overlaysProperties);
/**jsdoc
* 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
* whether its image has been loaded.
* @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>.
* @example <caption>Create an image overlay and report whether its image is loaded after 1s.</caption>
* var overlay = Overlays.addOverlay("image", {
@ -440,17 +427,17 @@ public slots:
* print("Image loaded: " + isLoaded);
* }, 1000);
*/
bool isLoaded(OverlayID id);
bool isLoaded(const QUuid& id);
/**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
* @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.
* @returns {Size} The size of the <code>text</code> if the overlay is a text 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
* overlay, the size is in meters.
* @example <caption>Calculate the size of "hello" in a 3D text overlay.</caption>
* @returns {Size} The size of the <code>text</code> if the object is a text entity or overlay, otherwise
* <code>{ height: 0, width : 0 }</code>. If the object is a 2D overlay, the size is in pixels; if the object is an entity,
* the size is in meters.
* @example <caption>Calculate the size of "hello" in a 3D text entity.</caption>
* var overlay = Overlays.addOverlay("text3d", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })),
* rotation: MyAvatar.orientation,
@ -460,7 +447,7 @@ public slots:
* var textSize = Overlays.textSize(overlay, "hello");
* print("Size of \"hello\": " + JSON.stringify(textSize));
*/
QSizeF textSize(OverlayID id, const QString& text);
QSizeF textSize(const QUuid& id, const QString& text);
/**jsdoc
* Get the width of the window or HUD.
@ -477,17 +464,17 @@ public slots:
float height();
/**jsdoc
* Check if there is an overlay of a given ID.
* Check if there is an object of a given ID.
* @function Overlays.isAddedOverlay
* @param {Uuid} overlayID - The ID to check.
* @returns {boolean} <code>true</code> if an overlay with the given ID exists, <code>false</code> otherwise.
* @param {Uuid} id - The ID to check.
* @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
* Generate a mouse press event on an overlay.
* @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.
* @example <caption>Create a 2D rectangle overlay plus a 3D cube overlay and generate mousePressOnOverlay events for the 2D
* 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
* Generate a mouse release event on an overlay.
* @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.
*/
void sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendMouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a mouse move event on an overlay.
* @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.
*/
void sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendMouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* 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 {PointerEvent} event - The hover enter event details.
*/
void sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendHoverEnterOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a hover over event on an overlay.
* @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.
*/
void sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendHoverOverOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Generate a hover leave event on an overlay.
* @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.
*/
void sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendHoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* Get the ID of the Web3D local entity that has keyboard focus.
@ -575,16 +562,16 @@ public slots:
/**jsdoc
* Set the Web3D local entity that has keyboard focus.
* @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.
*/
void Overlays::setKeyboardFocusOverlay(const EntityItemID& id) { DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusLocalEntity(id); }
void setKeyboardFocusOverlay(const EntityItemID& id) { DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusLocalEntity(id); }
signals:
/**jsdoc
* Triggered when an overlay is deleted.
* @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}
* @example <caption>Create an overlay then delete it after 1s.</caption>
* var overlay = Overlays.addOverlay("cube", {
@ -602,13 +589,13 @@ signals:
* Overlays.deleteOverlay(overlay);
* }, 1000);
*/
void overlayDeleted(OverlayID id);
void overlayDeleted(const QUuid& id);
/**jsdoc
* 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).
* @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.
* @returns {Signal}
* @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
* Triggered when a mouse double press event occurs on an overlay. Only occurs for 3D overlays.
* @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.
* @returns {Signal}
*/
void mouseDoublePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
void mouseDoublePressOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* 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).
* @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.
* @returns {Signal}
*/
void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
void mouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* 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).
* @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.
* @returns {Signal}
*/
void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
void mouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* 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
* {@link Overlays.sendHoverEnterOverlay|sendHoverEnterOverlay} for a 2D overlay).
* @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.
* @returns {Signal}
* @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);
* });
*/
void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event);
void hoverEnterOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* 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).
* @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.
* @returns {Signal}
*/
void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event);
void hoverOverOverlay(const QUuid& id, const PointerEvent& event);
/**jsdoc
* 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).
* @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.
* @returns {Signal}
*/
void hoverLeaveOverlay(OverlayID overlayID, const PointerEvent& event);
void hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
private:
void cleanupOverlaysToDelete();
mutable QMutex _mutex { QMutex::Recursive };
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
QMap<QUuid, Overlay::Pointer> _overlays;
QList<Overlay::Pointer> _overlaysToDelete;
unsigned int _stackOrder { 1 };
bool _enabled = true;
std::atomic<bool> _shuttingDown{ false };
bool _enabled { true };
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);
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
QUuid _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
QUuid _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
private slots:
void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
void mouseReleasePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
void hoverEnterPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
void hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
void hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
void mousePressPointerEvent(const QUuid& id, const PointerEvent& event);
void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event);
void mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event);
void hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event);
void hoverOverPointerEvent(const QUuid& id, const PointerEvent& event);
void hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event);
};
#endif // hifi_Overlays_h

View file

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

View file

@ -23,6 +23,9 @@ using namespace render;
using namespace render::entities;
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) :
Parent(entity),
@ -205,3 +208,12 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
dimensions.y - (_topMargin + _bottomMargin));
_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;
ShapeKey getShapeKey() override;
QSizeF textSize(const QString& text) const;
private:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const 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:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
@ -57,9 +60,6 @@ protected:
virtual bool wantsHandControllerPointerEvents() 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 handlePointerEventAsMouse(const PointerEvent& event);

View file

@ -571,7 +571,7 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin
return addEntity(properties);
}
QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) {
QUuid EntityScriptingInterface::cloneEntity(const QUuid& entityIDToClone) {
EntityItemID newEntityID;
EntityItemProperties properties = getEntityProperties(entityIDToClone);
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;
return getEntityProperties(entityID, noSpecificProperties);
}
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties) {
EntityItemProperties EntityScriptingInterface::getEntityProperties(const QUuid& entityID, EntityPropertyFlags desiredProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__);
bool scalesWithParent { false };
@ -775,7 +775,7 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri
return finalResult;
}
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
QUuid EntityScriptingInterface::editEntity(const QUuid& id, const EntityItemProperties& scriptSideProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__);
_activityTracking.editedEntityCount++;
@ -960,7 +960,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
return id;
}
void EntityScriptingInterface::deleteEntity(QUuid id) {
void EntityScriptingInterface::deleteEntity(const QUuid& id) {
PROFILE_RANGE(script_entities, __FUNCTION__);
_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) {
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
_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__);
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__);
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__);
auto scriptServerServices = DependencyManager::get<EntityScriptServerServices>();
@ -1262,7 +1299,7 @@ ParabolaToEntityIntersectionResult EntityScriptingInterface::evalParabolaInterse
return result;
}
bool EntityScriptingInterface::reloadServerScripts(QUuid entityID) {
bool EntityScriptingInterface::reloadServerScripts(const QUuid& entityID) {
auto client = DependencyManager::get<EntityScriptClient>();
return client->reloadServerScript(entityID);
}
@ -1335,7 +1372,7 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScript
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 handler = makeScopedHandlerObject(scopeOrCallback, methodOrName);
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 request = client->createScriptStatusRequest(entityID);
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;
}
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__);
return polyVoxWorker(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
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,
float radius, int value) {
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__);
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__);
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) {
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__);
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
@ -1580,7 +1617,7 @@ bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::v
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__);
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
@ -2040,7 +2077,7 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
return result;
}
bool EntityScriptingInterface::isChildOfParent(QUuid childID, QUuid parentID) {
bool EntityScriptingInterface::isChildOfParent(const QUuid& childID, const QUuid& parentID) {
bool isChild = false;
if (!_entityTree) {
@ -2062,7 +2099,7 @@ bool EntityScriptingInterface::isChildOfParent(QUuid childID, QUuid parentID) {
return isChild;
}
QString EntityScriptingInterface::getNestableType(QUuid id) {
QString EntityScriptingInterface::getNestableType(const QUuid& id) {
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) {
return "unknown";
@ -2164,7 +2201,7 @@ void EntityScriptingInterface::sendHoverLeaveEntity(const EntityItemID& id, cons
emit hoverLeaveEntity(id, event);
}
bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) {
bool EntityScriptingInterface::wantsHandControllerPointerEvents(const QUuid& id) {
bool result = false;
if (_entityTree) {
_entityTree->withReadLock([&] {
@ -2196,7 +2233,7 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons
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__);
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.
* @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
* Get the properties of an entity.
@ -315,8 +315,8 @@ public slots:
* var properties = Entities.getEntityProperties(entityID, ["color"]);
* print("Entity color: " + JSON.stringify(properties.color));
*/
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID);
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties);
Q_INVOKABLE EntityItemProperties getEntityProperties(const QUuid& entityID);
Q_INVOKABLE EntityItemProperties getEntityProperties(const QUuid& entityID, EntityPropertyFlags desiredProperties);
/**jsdoc
* Update an entity with specified properties.
@ -340,7 +340,7 @@ public slots:
* properties = Entities.getEntityProperties(entityID, ["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
* Delete an entity.
@ -358,8 +358,50 @@ public slots:
* Entities.deleteEntity(entityID);
* }, 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
* 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[]} [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
* 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[]} [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
* 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[]} [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());
/**jsdoc
@ -524,7 +566,7 @@ public slots:
* @returns {boolean} <code>true</code> if the reload request was successfully sent to the server, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool reloadServerScripts(QUuid entityID);
Q_INVOKABLE bool reloadServerScripts(const QUuid& entityID);
/**jsdoc
* 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
* information on the error.
*/
Q_INVOKABLE bool getServerScriptStatus(QUuid entityID, QScriptValue callback);
Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, QScriptValue callback);
/**jsdoc
* 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
* <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());
@ -657,7 +699,7 @@ public slots:
* Entities.setVoxelSphere(polyVox, position, 0.9, 255);
*/
// 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
* 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);
*/
// 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
* 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);
*/
// 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
* Set the values of all voxels in a {@link Entities.EntityType|PolyVox} entity.
@ -721,7 +763,7 @@ public slots:
* Entities.setAllVoxels(entity, 1);
*/
// 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
* 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);
*/
// 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
* Convert voxel coordinates in a {@link Entities.EntityType|PolyVox} entity to world coordinates. Voxel coordinates are
@ -862,7 +904,7 @@ public slots:
* ]);
* }, 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
* Append a point to a {@link Entities.EntityType|Line} entity.
@ -890,7 +932,7 @@ public slots:
* // Add a third point to create a "V".
* 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
* 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
*/
Q_INVOKABLE bool isChildOfParent(QUuid childID, QUuid parentID);
Q_INVOKABLE bool isChildOfParent(const QUuid& childID, const QUuid& parentID);
/**jsdoc
* 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(Uuid.generate())); // "unknown"
*/
Q_INVOKABLE QString getNestableType(QUuid entityID);
Q_INVOKABLE QString getNestableType(const QUuid& entityID);
/**jsdoc
* 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
* <code>false</code>.
*/
Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id);
Q_INVOKABLE bool wantsHandControllerPointerEvents(const QUuid& id);
/**jsdoc
* 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.
*/
// 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
* 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::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::MaterialLayer, const std::string&)> EntityTree::_addMaterialToOverlayOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromOverlayOperator = nullptr;
std::function<QSizeF(const QUuid&, const QString&)> EntityTree::_textSizeOperator = nullptr;
bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
if (_addMaterialToEntityOperator) {
@ -2988,18 +2987,11 @@ bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::Mater
return false;
}
bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
if (_addMaterialToOverlayOperator) {
return _addMaterialToOverlayOperator(overlayID, material, parentMaterialName);
QSizeF EntityTree::textSize(const QUuid& id, const QString& text) {
if (_textSizeOperator) {
return _textSizeOperator(id, text);
}
return false;
}
bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
if (_removeMaterialFromOverlayOperator) {
return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialName);
}
return false;
return QSizeF(0.0f, 0.0f);
}
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 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 setRemoveMaterialFromOverlayOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; }
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);
static void setTextSizeOperator(std::function<QSizeF(const QUuid&, const QString&)> textSizeOperator) { _textSizeOperator = textSizeOperator; }
static QSizeF textSize(const QUuid& id, const QString& text);
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::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
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<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromOverlayOperator;
static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
std::vector<int32_t> _staleProxies;