diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 780fad15f2..4e833f6b77 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -25,13 +25,13 @@ #include #include +#include #include #include #include #include #include #include -#include //for KillAvatarReason #include #include "DomainServerNodeData.h" @@ -870,14 +870,6 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointerwrite(nodeUUID.toRfc4122()); - packet->writePrimitive(KillAvatarReason::NoReason); - - // send to avatar mixer, it sends the kill to everyone else - limitedNodeList->broadcastToNodes(std::move(packet), NodeSet() << NodeType::AvatarMixer); - if (newPermissions) { qDebug() << "Removing connect permission for node" << uuidStringWithoutCurlyBraces(matchingNode->getUUID()) << "after kick request from" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ebc1176ee1..29d260cb5f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3773,9 +3773,12 @@ std::map Application::prepareServerlessDomainContents(QUrl dom tmpTree->reaverageOctreeElements(); tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0); } + std::map namedPaths = tmpTree->getNamedPaths(); - return tmpTree->getNamedPaths(); + // we must manually eraseAllOctreeElements(false) else the tmpTree will mem-leak + tmpTree->eraseAllOctreeElements(false); + return namedPaths; } void Application::loadServerlessDomain(QUrl domainURL) { @@ -4981,9 +4984,9 @@ void Application::idle() { { if (_keyboardFocusWaitingOnRenderable && getEntities()->renderableForEntityId(_keyboardFocusedEntity.get())) { - _keyboardFocusWaitingOnRenderable = false; QUuid entityId = _keyboardFocusedEntity.get(); setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + _keyboardFocusWaitingOnRenderable = false; setKeyboardFocusEntity(entityId); } } @@ -5770,6 +5773,11 @@ void Application::reloadResourceCaches() { DependencyManager::get()->reset(); // Force redownload of .fst models + DependencyManager::get()->reloadAllScripts(); + getOffscreenUI()->clearCache(); + + DependencyManager::get()->createKeyboard(); + getMyAvatar()->resetFullAvatarURL(); } diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index b020cdb627..260ff33db7 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -254,11 +254,15 @@ void AvatarProject::openInInventory() const { DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); tablet->loadQMLSource("hifi/commerce/wallet/Wallet.qml"); DependencyManager::get()->openTablet(); - tablet->getTabletRoot()->forceActiveFocus(); - auto name = getProjectName(); // I'm not a fan of this, but it's the only current option. + auto name = getProjectName(); QTimer::singleShot(TIME_TO_WAIT_FOR_INVENTORY_TO_OPEN_MS, [name, tablet]() { tablet->sendToQml(QVariantMap({ { "method", "updatePurchases" }, { "filterText", name } })); }); + + QQuickItem* root = tablet->getTabletRoot(); + if (root) { + root->forceActiveFocus(); + } } diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 1ff1c0248b..d344e27d54 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -259,6 +259,12 @@ void Keyboard::setUse3DKeyboard(bool use) { void Keyboard::createKeyboard() { auto pointerManager = DependencyManager::get(); + if (_created) { + pointerManager->removePointer(_leftHandStylus); + pointerManager->removePointer(_rightHandStylus); + clearKeyboardKeys(); + } + QVariantMap modelProperties { { "url", MALLET_MODEL_URL } }; @@ -289,6 +295,8 @@ void Keyboard::createKeyboard() { loadKeyboardFile(keyboardSvg); _keySound = DependencyManager::get()->getSound(SOUND_FILE); + + _created = true; } bool Keyboard::isRaised() const { diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 627eb68dfd..b3358e486d 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -193,6 +193,8 @@ private: QSet _itemsToIgnore; std::vector> _keyboardLayers; + + bool _created { false }; }; #endif diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 24c0986d09..e5cec70f64 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -50,11 +50,14 @@ ContextOverlayInterface::ContextOverlayInterface() { _entityPropertyFlags += PROP_OWNING_AVATAR_ID; auto entityScriptingInterface = DependencyManager::get().data(); - connect(entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity, this, &ContextOverlayInterface::clickDownOnEntity); - connect(entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity, this, &ContextOverlayInterface::holdingClickOnEntity); + connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::clickDownOnEntity); connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, &ContextOverlayInterface::mouseReleaseOnEntity); connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity); connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity); + + connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); + connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); + connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() { if (_contextOverlayJustClicked && _hmdScriptingInterface->isMounted()) { QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID(); @@ -70,8 +73,6 @@ ContextOverlayInterface::ContextOverlayInterface() { } }); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); - connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); - connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); { _selectionScriptingInterface->enableListHighlight("contextOverlayHighlightList", QVariantMap()); @@ -106,7 +107,7 @@ void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const Po if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(id)) { _mouseDownEntity = id; _mouseDownEntityTimestamp = usecTimestampNow(); - } else if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) { + } else if ((event.shouldFocus() || event.getButton() == PointerEvent::PrimaryButton) && id == _contextOverlayID) { qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id; emit contextOverlayClicked(_currentEntityWithContextOverlay); _contextOverlayJustClicked = true; @@ -119,13 +120,10 @@ void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const Po } static const float CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC = 400.0f; -void ContextOverlayInterface::holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { +void ContextOverlayInterface::mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { if (!_mouseDownEntity.isNull() && ((usecTimestampNow() - _mouseDownEntityTimestamp) > (CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC * USECS_PER_MSEC))) { _mouseDownEntity = EntityItemID(); } -} - -void ContextOverlayInterface::mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID) && _mouseDownEntity == entityItemID) { createOrDestroyContextOverlay(entityItemID, event); } @@ -253,7 +251,7 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt } void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event) { - if (_contextOverlayID != UNKNOWN_ENTITY_ID) { + if (_contextOverlayID == id) { qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id; EntityItemProperties properties; properties.setColor(CONTEXT_OVERLAY_COLOR); @@ -265,7 +263,7 @@ void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, } void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event) { - if (_contextOverlayID != UNKNOWN_ENTITY_ID) { + if (_contextOverlayID == id) { qCDebug(context_overlay) << "Stopped hovering over Context Overlay. ID:" << id; EntityItemProperties properties; properties.setColor(CONTEXT_OVERLAY_COLOR); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index 57fc8ebe6e..b1b62aa0c4 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -59,7 +59,6 @@ signals: public slots: void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 714db97bc2..bf79a46dcb 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -16,8 +16,7 @@ #include "Application.h" Overlay::Overlay() : - _renderItemID(render::Item::INVALID_ITEM_ID), - _visible(true) + _renderItemID(render::Item::INVALID_ITEM_ID) { } @@ -34,20 +33,6 @@ void Overlay::setProperties(const QVariantMap& properties) { } } -QVariant Overlay::getProperty(const QString& property) { - if (property == "type") { - return QVariant(getType()); - } - if (property == "id") { - return getID(); - } - if (property == "visible") { - return _visible; - } - - return QVariant(); -} - bool Overlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) { _renderItemID = scene->allocateID(); transaction.resetItem(_renderItemID, std::make_shared(overlay)); @@ -65,7 +50,7 @@ render::ItemKey Overlay::getKey() { builder.withViewSpace(); builder.withLayer(render::hifi::LAYER_2D); - if (!getVisible()) { + if (!_visible) { builder.withInvisible(); } diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index ee6e281193..72373d2d20 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -31,7 +31,6 @@ public: virtual render::ItemKey getKey(); virtual AABox getBounds() const = 0; - virtual bool supportsGetProperty() const { return true; } virtual bool addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction); virtual void removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction); @@ -42,17 +41,15 @@ public: // getters virtual QString getType() const = 0; - bool isLoaded() { return true; } bool getVisible() const { return _visible; } // setters - virtual void setVisible(bool visible) { _visible = visible; } + void setVisible(bool visible) { _visible = visible; } unsigned int getStackOrder() const { return _stackOrder; } void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; } - Q_INVOKABLE virtual void setProperties(const QVariantMap& properties); + Q_INVOKABLE virtual void setProperties(const QVariantMap& properties) = 0; Q_INVOKABLE virtual Overlay* createClone() const = 0; - Q_INVOKABLE virtual QVariant getProperty(const QString& property); render::ItemID getRenderItemID() const { return _renderItemID; } void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; } @@ -60,7 +57,7 @@ public: protected: render::ItemID _renderItemID { render::Item::INVALID_ITEM_ID }; - bool _visible; + bool _visible { true }; unsigned int _stackOrder { 0 }; private: diff --git a/interface/src/ui/overlays/Overlay2D.cpp b/interface/src/ui/overlays/Overlay2D.cpp index 71b74e9452..91c7198e49 100644 --- a/interface/src/ui/overlays/Overlay2D.cpp +++ b/interface/src/ui/overlays/Overlay2D.cpp @@ -65,24 +65,4 @@ void Overlay2D::setProperties(const QVariantMap& properties) { } setBounds(newBounds); } -} - -QVariant Overlay2D::getProperty(const QString& property) { - if (property == "bounds") { - return qRectToVariant(_bounds); - } - if (property == "x") { - return _bounds.x(); - } - if (property == "y") { - return _bounds.y(); - } - if (property == "width") { - return _bounds.width(); - } - if (property == "height") { - return _bounds.height(); - } - - return Overlay::getProperty(property); -} +} \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlay2D.h b/interface/src/ui/overlays/Overlay2D.h index 54ab52b469..cfcb114398 100644 --- a/interface/src/ui/overlays/Overlay2D.h +++ b/interface/src/ui/overlays/Overlay2D.h @@ -26,10 +26,6 @@ public: virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return 1; } // getters - int getX() const { return _bounds.x(); } - int getY() const { return _bounds.y(); } - int getWidth() const { return _bounds.width(); } - int getHeight() const { return _bounds.height(); } const QRect& getBoundingRect() const { return _bounds; } // setters @@ -40,7 +36,6 @@ public: void setBounds(const QRect& bounds) { _bounds = bounds; } void setProperties(const QVariantMap& properties) override; - QVariant getProperty(const QString& property) override; protected: QRect _bounds; // where on the screen to draw diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 9b2f741531..8fd5d236a0 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -772,29 +772,29 @@ QUuid Overlays::addOverlay(const QString& type, const QVariant& properties) { return UNKNOWN_ENTITY_ID; } - if (QThread::currentThread() != thread()) { - QUuid result; - PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(QUuid, result), Q_ARG(const QString&, type), Q_ARG(const QVariant&, properties)); - return result; - } - - Overlay::Pointer overlay; - if (type == ImageOverlay::TYPE) { + if (type == ImageOverlay::TYPE || type == TextOverlay::TYPE || type == RectangleOverlay::TYPE) { #if !defined(DISABLE_QML) - overlay = Overlay::Pointer(new ImageOverlay(), [](Overlay* ptr) { ptr->deleteLater(); }); -#endif - } else if (type == TextOverlay::TYPE) { -#if !defined(DISABLE_QML) - overlay = Overlay::Pointer(new TextOverlay(), [](Overlay* ptr) { ptr->deleteLater(); }); -#endif - } else if (type == RectangleOverlay::TYPE) { - overlay = Overlay::Pointer(new RectangleOverlay(), [](Overlay* ptr) { ptr->deleteLater(); }); - } + if (QThread::currentThread() != thread()) { + QUuid result; + PROFILE_RANGE(script, __FUNCTION__); + BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(QUuid, result), Q_ARG(const QString&, type), Q_ARG(const QVariant&, properties)); + return result; + } - if (overlay) { - overlay->setProperties(properties.toMap()); - return add2DOverlay(overlay); + Overlay::Pointer overlay; + if (type == ImageOverlay::TYPE) { + overlay = Overlay::Pointer(new ImageOverlay(), [](Overlay* ptr) { ptr->deleteLater(); }); + } else if (type == TextOverlay::TYPE) { + overlay = Overlay::Pointer(new TextOverlay(), [](Overlay* ptr) { ptr->deleteLater(); }); + } else if (type == RectangleOverlay::TYPE) { + overlay = Overlay::Pointer(new RectangleOverlay(), [](Overlay* ptr) { ptr->deleteLater(); }); + } + if (overlay) { + overlay->setProperties(properties.toMap()); + return add2DOverlay(overlay); + } +#endif + return QUuid(); } QString entityType = overlayToEntityType(type); @@ -835,15 +835,14 @@ QUuid Overlays::cloneOverlay(const QUuid& id) { return UNKNOWN_ENTITY_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) { + 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; + } return add2DOverlay(Overlay::Pointer(overlay->createClone(), [](Overlay* ptr) { ptr->deleteLater(); })); } @@ -919,6 +918,11 @@ void Overlays::deleteOverlay(const QUuid& id) { Overlay::Pointer overlay = take2DOverlay(id); if (overlay) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "deleteOverlay", Q_ARG(const QUuid&, id)); + return; + } + _overlaysToDelete.push_back(overlay); emit overlayDeleted(id); return; @@ -933,15 +937,14 @@ QString Overlays::getOverlayType(const QUuid& id) { return ""; } - if (QThread::currentThread() != thread()) { - QString result; - PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(const QUuid&, id)); - return result; - } - Overlay::Pointer overlay = get2DOverlay(id); if (overlay) { + if (QThread::currentThread() != thread()) { + QString result; + PROFILE_RANGE(script, __FUNCTION__); + BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(const QUuid&, id)); + return result; + } return overlay->getType(); } @@ -949,15 +952,14 @@ QString Overlays::getOverlayType(const QUuid& 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(const QUuid&, id)); - return result; - } - Overlay::Pointer overlay = get2DOverlay(id); if (overlay) { + if (QThread::currentThread() != thread()) { + QObject* result; + PROFILE_RANGE(script, __FUNCTION__); + BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(const QUuid&, id)); + return result; + } return qobject_cast(&(*overlay)); } @@ -969,6 +971,12 @@ QUuid Overlays::getOverlayAtPoint(const glm::vec2& point) { return UNKNOWN_ENTITY_ID; } + if (QThread::currentThread() != thread()) { + QUuid result; + BLOCKING_INVOKE_METHOD(this, "getOverlayAtPoint", Q_RETURN_ARG(QUuid, result), Q_ARG(const glm::vec2&, point)); + return result; + } + QMutexLocker locker(&_mutex); QMapIterator i(_overlays); unsigned int bestStackOrder = 0; @@ -976,8 +984,7 @@ QUuid Overlays::getOverlayAtPoint(const glm::vec2& point) { while (i.hasNext()) { i.next(); auto thisOverlay = std::dynamic_pointer_cast(i.value()); - if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() && - thisOverlay->getBoundingRect().contains(point.x, point.y, false)) { + if (thisOverlay && thisOverlay->getVisible() && thisOverlay->getBoundingRect().contains(point.x, point.y, false)) { if (thisOverlay->getStackOrder() > bestStackOrder) { bestID = i.key(); bestStackOrder = thisOverlay->getStackOrder(); @@ -991,9 +998,7 @@ QUuid Overlays::getOverlayAtPoint(const glm::vec2& point) { QVariant Overlays::getProperty(const QUuid& id, const QString& property) { Overlay::Pointer overlay = get2DOverlay(id); if (overlay) { - if (overlay->supportsGetProperty()) { - return overlay->getProperty(property); - } + // We don't support getting properties from QML Overlays right now return QVariant(); } @@ -1009,12 +1014,8 @@ QVariantMap Overlays::getProperties(const QUuid& id, const QStringList& properti Overlay::Pointer overlay = get2DOverlay(id); QVariantMap result; if (overlay) { - if (overlay->supportsGetProperty()) { - for (const auto& property : properties) { - result.insert(property, overlay->getProperty(property)); - } - } - return result; + // We don't support getting properties from QML Overlays right now + return QVariantMap(); } QVariantMap overlayProperties = convertEntityToOverlayProperties(DependencyManager::get()->getEntityProperties(id)); @@ -1141,38 +1142,30 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R } 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(const QUuid&, id)); - return result; - } - Overlay::Pointer overlay = get2DOverlay(id); if (overlay) { - return overlay->isLoaded(); + return true; } return DependencyManager::get()->isLoaded(id); } 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(const QUuid&, id), Q_ARG(QString, text)); - return result; - } - Overlay::Pointer overlay = get2DOverlay(id); if (overlay) { + if (QThread::currentThread() != thread()) { + QSizeF result; + PROFILE_RANGE(script, __FUNCTION__); + BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(const QUuid&, id), Q_ARG(QString, text)); + return result; + } if (auto textOverlay = std::dynamic_pointer_cast(overlay)) { return textOverlay->textSize(text); } return QSizeF(0.0f, 0.0f); - } else { - return DependencyManager::get()->textSize(id, text); } + + return DependencyManager::get()->textSize(id, text); } bool Overlays::isAddedOverlay(const QUuid& id) { diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp index 537c421ca7..f301a23d49 100644 --- a/interface/src/ui/overlays/QmlOverlay.cpp +++ b/interface/src/ui/overlays/QmlOverlay.cpp @@ -57,29 +57,15 @@ QmlOverlay::~QmlOverlay() { // QmlOverlay replaces Overlay's properties with those defined in the QML file used but keeps Overlay2D's properties. void QmlOverlay::setProperties(const QVariantMap& properties) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setProperties", Q_ARG(QVariantMap, properties)); - return; - } - Overlay2D::setProperties(properties); - auto bounds = _bounds; + // check to see if qmlElement still exists if (_qmlElement) { - _qmlElement->setX(bounds.left()); - _qmlElement->setY(bounds.top()); - _qmlElement->setWidth(bounds.width()); - _qmlElement->setHeight(bounds.height()); + _qmlElement->setX(_bounds.left()); + _qmlElement->setY(_bounds.top()); + _qmlElement->setWidth(_bounds.width()); + _qmlElement->setHeight(_bounds.height()); + _qmlElement->setVisible(_visible); QMetaObject::invokeMethod(_qmlElement, "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); } -} - -void QmlOverlay::render(RenderArgs* args) { - if (!_qmlElement) { - return; - } - - if (_visible != _qmlElement->isVisible()) { - _qmlElement->setVisible(_visible); - } -} +} \ No newline at end of file diff --git a/interface/src/ui/overlays/QmlOverlay.h b/interface/src/ui/overlays/QmlOverlay.h index 0951a04772..32badde28b 100644 --- a/interface/src/ui/overlays/QmlOverlay.h +++ b/interface/src/ui/overlays/QmlOverlay.h @@ -25,10 +25,8 @@ public: QmlOverlay(const QUrl& url, const QmlOverlay* overlay); ~QmlOverlay(); - bool supportsGetProperty() const override { return false; } - void setProperties(const QVariantMap& properties) override; - void render(RenderArgs* args) override; + void render(RenderArgs* args) override {} private: Q_INVOKABLE void qmlElementDestroyed(); diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index da5e9b6508..9b87d058fd 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -95,57 +95,85 @@ void AnimClip::setCurrentFrameInternal(float frame) { _frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers); } +static std::vector buildJointIndexMap(const AnimSkeleton& dstSkeleton, const AnimSkeleton& srcSkeleton) { + std::vector jointIndexMap; + int srcJointCount = srcSkeleton.getNumJoints(); + jointIndexMap.reserve(srcJointCount); + for (int srcJointIndex = 0; srcJointIndex < srcJointCount; srcJointIndex++) { + QString srcJointName = srcSkeleton.getJointName(srcJointIndex); + int dstJointIndex = dstSkeleton.nameToJointIndex(srcJointName); + jointIndexMap.push_back(dstJointIndex); + } + return jointIndexMap; +} + void AnimClip::copyFromNetworkAnim() { assert(_networkAnim && _networkAnim->isLoaded() && _skeleton); _anim.clear(); auto avatarSkeleton = getSkeleton(); - - // build a mapping from animation joint indices to avatar joint indices. - // by matching joints with the same name. const HFMModel& animModel = _networkAnim->getHFMModel(); AnimSkeleton animSkeleton(animModel); const int animJointCount = animSkeleton.getNumJoints(); const int avatarJointCount = avatarSkeleton->getNumJoints(); - std::vector animToAvatarJointIndexMap; - animToAvatarJointIndexMap.reserve(animJointCount); - for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) { - QString animJointName = animSkeleton.getJointName(animJointIndex); - int avatarJointIndex = avatarSkeleton->nameToJointIndex(animJointName); - animToAvatarJointIndexMap.push_back(avatarJointIndex); - } + + // build a mapping from animation joint indices to avatar joint indices by matching joints with the same name. + std::vector avatarToAnimJointIndexMap = buildJointIndexMap(animSkeleton, *avatarSkeleton); const int animFrameCount = animModel.animationFrames.size(); _anim.resize(animFrameCount); for (int frame = 0; frame < animFrameCount; frame++) { - const HFMAnimationFrame& animFrame = animModel.animationFrames[frame]; - // init all joints in animation to default pose - // this will give us a resonable result for bones in the avatar skeleton but not in the animation. - _anim[frame].reserve(avatarJointCount); - for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) { - _anim[frame].push_back(avatarSkeleton->getRelativeDefaultPose(avatarJointIndex)); + // extract the full rotations from the animFrame (including pre and post rotations from the animModel). + std::vector animRotations; + animRotations.reserve(animJointCount); + for (int i = 0; i < animJointCount; i++) { + animRotations.push_back(animModel.joints[i].preRotation * animFrame.rotations[i] * animModel.joints[i].postRotation); } - for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) { - int avatarJointIndex = animToAvatarJointIndexMap[animJointIndex]; + // convert rotations into absolute frame + animSkeleton.convertRelativeRotationsToAbsolute(animRotations); - // skip joints that are in the animation but not in the avatar. - if (avatarJointIndex >= 0 && avatarJointIndex < avatarJointCount) { + // build absolute rotations for the avatar + std::vector avatarRotations; + avatarRotations.reserve(avatarJointCount); + for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) { + int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex]; + if (animJointIndex >= 0) { + // This joint is in both animation and avatar. + // Set the absolute rotation directly + avatarRotations.push_back(animRotations[animJointIndex]); + } else { + // This joint is NOT in the animation at all. + // Set it so that the default relative rotation remains unchanged. + glm::quat avatarRelativeDefaultRot = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex).rot(); + glm::quat avatarParentAbsoluteRot; + int avatarParentJointIndex = avatarSkeleton->getParentIndex(avatarJointIndex); + if (avatarParentJointIndex >= 0) { + avatarParentAbsoluteRot = avatarRotations[avatarParentJointIndex]; + } + avatarRotations.push_back(avatarParentAbsoluteRot * avatarRelativeDefaultRot); + } + } + // convert avatar rotations into relative frame + avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations); + + _anim[frame].reserve(avatarJointCount); + + for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) { + const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex); + + // copy scale over from avatar default pose + glm::vec3 relativeScale = avatarDefaultPose.scale(); + + glm::vec3 relativeTranslation; + int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex]; + if (animJointIndex >= 0) { + // This joint is in both animation and avatar. const glm::vec3& animTrans = animFrame.translations[animJointIndex]; - const glm::quat& animRot = animFrame.rotations[animJointIndex]; - - const AnimPose& animPreRotPose = animSkeleton.getPreRotationPose(animJointIndex); - AnimPose animPostRotPose = animSkeleton.getPostRotationPose(animJointIndex); - AnimPose animRotPose(glm::vec3(1.0f), animRot, glm::vec3()); - - // adjust anim scale to equal the scale from the avatar joint. - // we do not support animated scale. - const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex); - animPostRotPose.scale() = avatarDefaultPose.scale(); // retarget translation from animation to avatar const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex]; @@ -192,11 +220,15 @@ void AnimClip::copyFromNetworkAnim() { } } - AnimPose animTransPose = AnimPose(glm::vec3(1.0f), glm::quat(), avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans)); - - _anim[frame][avatarJointIndex] = animTransPose * animPreRotPose * animRotPose * animPostRotPose; - + relativeTranslation = avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans); + } else { + // This joint is NOT in the animation at all. + // preserve the default translation. + relativeTranslation = avatarDefaultPose.trans(); } + + // build the final pose + _anim[frame].push_back(AnimPose(relativeScale, avatarRotations[avatarJointIndex], relativeTranslation)); } } diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index f7b5fa8c83..b26d00d8d0 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -152,8 +152,19 @@ void AnimSkeleton::convertAbsolutePosesToRelative(AnimPoseVec& poses) const { } } +void AnimSkeleton::convertRelativeRotationsToAbsolute(std::vector& rotations) const { + // rotations start off relative and leave in absolute frame + int lastIndex = std::min((int)rotations.size(), _jointsSize); + for (int i = 0; i < lastIndex; ++i) { + int parentIndex = _parentIndices[i]; + if (parentIndex != -1) { + rotations[i] = rotations[parentIndex] * rotations[i]; + } + } +} + void AnimSkeleton::convertAbsoluteRotationsToRelative(std::vector& rotations) const { - // poses start off absolute and leave in relative frame + // rotations start off absolute and leave in relative frame int lastIndex = std::min((int)rotations.size(), _jointsSize); for (int i = lastIndex - 1; i >= 0; --i) { int parentIndex = _parentIndices[i]; diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index dcb35ac9cb..efc1c1599f 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -55,6 +55,7 @@ public: void convertRelativePosesToAbsolute(AnimPoseVec& poses) const; void convertAbsolutePosesToRelative(AnimPoseVec& poses) const; + void convertRelativeRotationsToAbsolute(std::vector& rotations) const; void convertAbsoluteRotationsToRelative(std::vector& rotations) const; void saveNonMirroredPoses(const AnimPoseVec& poses) const; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index efd1399f30..e54258fc3e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -232,8 +232,6 @@ void EntityTreeRenderer::clearNonLocalEntities() { } } scene->enqueueTransaction(transaction); - } else { - qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown"; } _renderablesToUpdate = savedEntities; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 0f2c708d17..3b615ba467 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -266,6 +266,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene _webSurface->resize(QSize(windowSize.x, windowSize.y)); updateModelTransformAndBound(); _renderTransform = getModelTransform(); + _renderTransform.setScale(1.0f); _renderTransform.postScale(entity->getScaledDimensions()); }); }); @@ -487,4 +488,4 @@ QObject* WebEntityRenderer::getEventHandler() { void WebEntityRenderer::emitScriptEvent(const QVariant& message) { emit scriptEventReceived(message); -} \ No newline at end of file +} diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5dc218bc3b..5da1c05aa2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -79,6 +79,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param // Core requestedProperties += PROP_SIMULATION_OWNER; + requestedProperties += PROP_PARENT_ID; + requestedProperties += PROP_PARENT_JOINT_INDEX; requestedProperties += PROP_VISIBLE; requestedProperties += PROP_NAME; requestedProperties += PROP_LOCKED; @@ -93,8 +95,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_LAST_EDITED_BY; requestedProperties += PROP_ENTITY_HOST_TYPE; requestedProperties += PROP_OWNING_AVATAR_ID; - requestedProperties += PROP_PARENT_ID; - requestedProperties += PROP_PARENT_JOINT_INDEX; requestedProperties += PROP_QUERY_AA_CUBE; requestedProperties += PROP_CAN_CAST_SHADOW; requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; @@ -260,6 +260,14 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // PROP_CUSTOM_PROPERTIES_INCLUDED, APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); + // convert AVATAR_SELF_ID to actual sessionUUID. + QUuid actualParentID = getParentID(); + if (actualParentID == AVATAR_SELF_ID) { + auto nodeList = DependencyManager::get(); + actualParentID = nodeList->getSessionUUID(); + } + APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, actualParentID); + APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); @@ -274,14 +282,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, getLastEditedBy()); // APPEND_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, (uint32_t)getEntityHostType()); // not sent over the wire // APPEND_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, getOwningAvatarID()); // not sent over the wire - // convert AVATAR_SELF_ID to actual sessionUUID. - QUuid actualParentID = getParentID(); - if (actualParentID == AVATAR_SELF_ID) { - auto nodeList = DependencyManager::get(); - actualParentID = nodeList->getSessionUUID(); - } - APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, actualParentID); - APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex()); APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, getQueryAACube()); APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, getCanCastShadow()); // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, getIsVisibleInSecondaryCamera()); // not sent over the wire @@ -792,6 +792,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // Core // PROP_SIMULATION_OWNER handled above + { // parentID and parentJointIndex are protected by simulation ownership + bool oldOverwrite = overwriteLocalData; + overwriteLocalData = overwriteLocalData && !weOwnSimulation; + READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + overwriteLocalData = oldOverwrite; + } READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); @@ -835,13 +842,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); // READ_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, entity::HostType, setEntityHostType); // not sent over the wire // READ_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, QUuuid, setOwningAvatarID); // not sent over the wire - { // parentID and parentJointIndex are protected by simulation ownership - bool oldOverwrite = overwriteLocalData; - overwriteLocalData = overwriteLocalData && !weOwnSimulation; - READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); - READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); - overwriteLocalData = oldOverwrite; - } { // See comment above auto customUpdateQueryAACubeFromNetwork = [this, shouldUpdate, lastEdited](AACube value) { if (shouldUpdate(_lastUpdatedQueryAACubeTimestamp, value != _lastUpdatedQueryAACubeValue)) { @@ -1309,6 +1309,8 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire // Core COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); @@ -1323,8 +1325,6 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(lastEditedBy, getLastEditedBy); COPY_ENTITY_PROPERTY_TO_PROPERTIES(entityHostType, getEntityHostType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(owningAvatarID, getOwningAvatarID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); COPY_ENTITY_PROPERTY_TO_PROPERTIES(queryAACube, getQueryAACube); COPY_ENTITY_PROPERTY_TO_PROPERTIES(canCastShadow, getCanCastShadow); COPY_ENTITY_PROPERTY_TO_PROPERTIES(isVisibleInSecondaryCamera, isVisibleInSecondaryCamera); @@ -1456,6 +1456,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { // Core SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); @@ -1470,8 +1472,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy); SET_ENTITY_PROPERTY_FROM_PROPERTIES(entityHostType, setEntityHostType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(owningAvatarID, setOwningAvatarID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube); SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0ca851e228..bd1977f053 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -197,7 +197,7 @@ public: void setDescription(const QString& value); /// Dimensions in meters (0.0 - TREE_SCALE) - glm::vec3 getScaledDimensions() const; + virtual glm::vec3 getScaledDimensions() const; virtual void setScaledDimensions(const glm::vec3& value); virtual glm::vec3 getRaycastDimensions() const { return getScaledDimensions(); } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7575763bf9..5ae9b30869 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -462,6 +462,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { // Core CHECK_PROPERTY_CHANGE(PROP_SIMULATION_OWNER, simulationOwner); + CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); CHECK_PROPERTY_CHANGE(PROP_NAME, name); CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); @@ -476,8 +478,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LAST_EDITED_BY, lastEditedBy); CHECK_PROPERTY_CHANGE(PROP_ENTITY_HOST_TYPE, entityHostType); CHECK_PROPERTY_CHANGE(PROP_OWNING_AVATAR_ID, owningAvatarID); - CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); - CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); CHECK_PROPERTY_CHANGE(PROP_QUERY_AA_CUBE, queryAACube); CHECK_PROPERTY_CHANGE(PROP_CAN_CAST_SHADOW, canCastShadow); CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); @@ -1551,6 +1551,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Core properties //COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SIMULATION_OWNER, simulationOwner); // not exposed yet + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); @@ -1565,8 +1567,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LAST_EDITED_BY, lastEditedBy); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ENTITY_HOST_TYPE, entityHostType, getEntityHostTypeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); @@ -1956,6 +1956,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool // not handled yet // COPY_PROPERTY_FROM_QSCRIPTVALUE(simulationOwner, SimulationOwner, setSimulationOwner); } + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked); @@ -1972,8 +1974,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(entityHostType, EntityHostType); COPY_PROPERTY_FROM_QSCRIPTVALUE(owningAvatarID, QUuid, setOwningAvatarID); } - COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); COPY_PROPERTY_FROM_QSCRIPTVALUE(queryAACube, AACube, setQueryAACube); // TODO: should scripts be able to set this? COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow); COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera); @@ -2243,6 +2243,8 @@ void EntityItemProperties::copyFromJSONString(QScriptEngine& scriptEngine, const void EntityItemProperties::merge(const EntityItemProperties& other) { // Core COPY_PROPERTY_IF_CHANGED(simulationOwner); + COPY_PROPERTY_IF_CHANGED(parentID); + COPY_PROPERTY_IF_CHANGED(parentJointIndex); COPY_PROPERTY_IF_CHANGED(visible); COPY_PROPERTY_IF_CHANGED(name); COPY_PROPERTY_IF_CHANGED(locked); @@ -2257,8 +2259,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(lastEditedBy); COPY_PROPERTY_IF_CHANGED(entityHostType); COPY_PROPERTY_IF_CHANGED(owningAvatarID); - COPY_PROPERTY_IF_CHANGED(parentID); - COPY_PROPERTY_IF_CHANGED(parentJointIndex); COPY_PROPERTY_IF_CHANGED(queryAACube); COPY_PROPERTY_IF_CHANGED(canCastShadow); COPY_PROPERTY_IF_CHANGED(isVisibleInSecondaryCamera); @@ -2526,6 +2526,8 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr std::call_once(initMap, []() { // Core ADD_PROPERTY_TO_MAP(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner); + ADD_PROPERTY_TO_MAP(PROP_PARENT_ID, ParentID, parentID, QUuid); + ADD_PROPERTY_TO_MAP(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, uint16_t); ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool); ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); ADD_PROPERTY_TO_MAP(PROP_LOCKED, Locked, locked, bool); @@ -2541,8 +2543,6 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_PROPERTY_TO_MAP(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid); ADD_PROPERTY_TO_MAP(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType); ADD_PROPERTY_TO_MAP(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid); - ADD_PROPERTY_TO_MAP(PROP_PARENT_ID, ParentID, parentID, QUuid); - ADD_PROPERTY_TO_MAP(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, uint16_t); ADD_PROPERTY_TO_MAP(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube); ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool); @@ -2998,6 +2998,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, properties._simulationOwner.toByteArray()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); @@ -3012,8 +3014,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, properties.getLastEditedBy()); // APPEND_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, (uint32_t)properties.getEntityHostType()); // not sent over the wire // APPEND_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, properties.getOwningAvatarID()); // not sent over the wire - APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex()); APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, properties.getQueryAACube()); APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, properties.getCanCastShadow()); // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, properties.getIsVisibleInSecondaryCamera()); // not sent over the wire @@ -3124,6 +3124,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, properties.getModelURL()); + APPEND_ENTITY_PROPERTY(PROP_MODEL_SCALE, properties.getModelScale()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, properties.getJointRotationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, properties.getJointRotations()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, properties.getJointTranslationsSet()); @@ -3477,6 +3478,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int processedBytes += propertyFlags.getEncodedLength(); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATION_OWNER, QByteArray, setSimulationOwner); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); @@ -3491,8 +3494,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ENTITY_HOST_TYPE, entity::HostType, setEntityHostType); // not sent over the wire // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_OWNING_AVATAR_ID, QUuid, setOwningAvatarID); // not sent over the wire - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUERY_AA_CUBE, AACube, setQueryAACube); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // not sent over the wire @@ -3599,6 +3600,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_URL, QString, setModelURL); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_SCALE, vec3, setModelScale); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS, QVector, setJointRotations); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); @@ -3884,6 +3886,8 @@ bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, in void EntityItemProperties::markAllChanged() { // Core _simulationOwnerChanged = true; + _parentIDChanged = true; + _parentJointIndexChanged = true; _visibleChanged = true; _nameChanged = true; _lockedChanged = true; @@ -3898,8 +3902,6 @@ void EntityItemProperties::markAllChanged() { _lastEditedByChanged = true; _entityHostTypeChanged = true; _owningAvatarIDChanged = true; - _parentIDChanged = true; - _parentJointIndexChanged = true; _queryAACubeChanged = true; _canCastShadowChanged = true; _isVisibleInSecondaryCameraChanged = true; @@ -4232,6 +4234,12 @@ QList EntityItemProperties::listChangedProperties() { if (simulationOwnerChanged()) { out += "simulationOwner"; } + if (parentIDChanged()) { + out += "parentID"; + } + if (parentJointIndexChanged()) { + out += "parentJointIndex"; + } if (visibleChanged()) { out += "visible"; } @@ -4274,12 +4282,6 @@ QList EntityItemProperties::listChangedProperties() { if (owningAvatarIDChanged()) { out += "owningAvatarID"; } - if (parentIDChanged()) { - out += "parentID"; - } - if (parentJointIndexChanged()) { - out += "parentJointIndex"; - } if (queryAACubeChanged()) { out += "queryAACube"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index afc3537559..00a93dd129 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -161,6 +161,8 @@ public: // Core Properties DEFINE_PROPERTY_REF(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner, SimulationOwner()); + DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); + DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, -1); DEFINE_PROPERTY(PROP_VISIBLE, Visible, visible, bool, ENTITY_ITEM_DEFAULT_VISIBLE); DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString, ENTITY_ITEM_DEFAULT_NAME); DEFINE_PROPERTY(PROP_LOCKED, Locked, locked, bool, ENTITY_ITEM_DEFAULT_LOCKED); @@ -175,8 +177,6 @@ public: DEFINE_PROPERTY_REF(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid, ENTITY_ITEM_DEFAULT_LAST_EDITED_BY); DEFINE_PROPERTY_REF_ENUM(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType, entity::HostType::DOMAIN); DEFINE_PROPERTY_REF_WITH_SETTER(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, -1); DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube()); DEFINE_PROPERTY(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool, ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW); DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index cce30c9614..0326268f55 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -20,6 +20,8 @@ enum EntityPropertyList { // Core properties PROP_SIMULATION_OWNER, + PROP_PARENT_ID, + PROP_PARENT_JOINT_INDEX, PROP_VISIBLE, PROP_NAME, PROP_LOCKED, @@ -34,8 +36,6 @@ enum EntityPropertyList { PROP_LAST_EDITED_BY, PROP_ENTITY_HOST_TYPE, // not sent over the wire PROP_OWNING_AVATAR_ID, // not sent over the wire - PROP_PARENT_ID, - PROP_PARENT_JOINT_INDEX, PROP_QUERY_AA_CUBE, PROP_CAN_CAST_SHADOW, PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 53b4fb4fe4..6e404ce690 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -52,7 +52,15 @@ EntityTree::EntityTree(bool shouldReaverage) : } EntityTree::~EntityTree() { - eraseAllOctreeElements(false); + // NOTE: to eraseAllOctreeElements() in this context is useless because + // any OctreeElements in the tree still have shared backpointers to this Tree + // which means the dtor never would have been called in the first place! + // + // I'm keeping this useless commented-out line to remind us: + // we don't need shared pointer overhead for EntityTrees. + // TODO: EntityTreeElement::_tree should be raw back pointer. + // AND: EntityItem::_element should be a raw back pointer. + //eraseAllOctreeElements(false); // KEEP THIS } void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) { @@ -74,16 +82,15 @@ void EntityTree::eraseNonLocalEntities() { emit clearingEntities(); if (_simulation) { - // This will clear all entities host types including local entities, because local entities - // are not in the physics simulation + // local entities are not in the simulation, so we clear ALL _simulation->clearEntities(); } - _staleProxies.clear(); - QHash localMap; - localMap.swap(_entityMap); - QHash savedEntities; this->withWriteLock([&] { - foreach(EntityItemPointer entity, localMap) { + QHash savedEntities; + // NOTE: lock the Tree first, then lock the _entityMap. + // It should never be done the other way around. + QReadLocker locker(&_entityMapLock); + foreach(EntityItemPointer entity, _entityMap) { EntityTreeElementPointer element = entity->getElement(); if (element) { element->cleanupNonLocalEntities(); @@ -91,11 +98,16 @@ void EntityTree::eraseNonLocalEntities() { if (entity->isLocalEntity()) { savedEntities[entity->getEntityItemID()] = entity; + } else { + int32_t spaceIndex = entity->getSpaceIndex(); + if (spaceIndex != -1) { + // stale spaceIndices will be freed later + _staleProxies.push_back(spaceIndex); + } } } + _entityMap.swap(savedEntities); }); - localMap.clear(); - _entityMap = savedEntities; resetClientEditStats(); clearDeletedEntities(); @@ -113,13 +125,13 @@ void EntityTree::eraseNonLocalEntities() { _needsParentFixup = localEntitiesNeedsParentFixup; } } + void EntityTree::eraseAllOctreeElements(bool createNewRoot) { emit clearingEntities(); if (_simulation) { _simulation->clearEntities(); } - _staleProxies.clear(); QHash localMap; localMap.swap(_entityMap); this->withWriteLock([&] { @@ -128,6 +140,11 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) { if (element) { element->cleanupEntities(); } + int32_t spaceIndex = entity->getSpaceIndex(); + if (spaceIndex != -1) { + // assume stale spaceIndices will be freed later + _staleProxies.push_back(spaceIndex); + } } }); localMap.clear(); @@ -764,9 +781,9 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) _simulation->prepareEntityForDelete(theEntity); } - // keep a record of valid stale spaceIndices so they can be removed from the Space int32_t spaceIndex = theEntity->getSpaceIndex(); if (spaceIndex != -1) { + // stale spaceIndices will be freed later _staleProxies.push_back(spaceIndex); } } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index bb8f375302..505ee26c0f 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -301,6 +301,31 @@ void ModelEntityItem::setModelURL(const QString& url) { }); } +glm::vec3 ModelEntityItem::getScaledDimensions() const { + glm::vec3 parentScale = getTransform().getScale(); + return _unscaledDimensions * parentScale; +} + +void ModelEntityItem::setScaledDimensions(const glm::vec3& value) { + glm::vec3 parentScale = getTransform().getScale(); + setUnscaledDimensions(value / parentScale); +} + +const Transform ModelEntityItem::getTransform() const { + bool success; + return getTransform(success); +} + +const Transform ModelEntityItem::getTransform(bool& success, int depth) const { + const Transform parentTransform = getParentTransform(success, depth); + Transform localTransform = getLocalTransform(); + localTransform.postScale(getModelScale()); + + Transform worldTransform; + Transform::mult(worldTransform, parentTransform, localTransform); + + return worldTransform; +} void ModelEntityItem::setCompoundShapeURL(const QString& url) { withWriteLock([&] { if (_compoundShapeURL.get() != url) { @@ -715,13 +740,13 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp } glm::vec3 ModelEntityItem::getModelScale() const { - return _modelScaleLock.resultWithReadLock([&] { - return getSNScale(); + return resultWithReadLock([&] { + return _modelScale; }); } void ModelEntityItem::setModelScale(const glm::vec3& modelScale) { - _modelScaleLock.withWriteLock([&] { - setSNScale(modelScale); + withWriteLock([&] { + _modelScale = modelScale; }); -} \ No newline at end of file +} diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 234cfa435e..0efbbbb16c 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -66,6 +66,12 @@ public: static const QString DEFAULT_MODEL_URL; QString getModelURL() const; + virtual glm::vec3 getScaledDimensions() const override; + virtual void setScaledDimensions(const glm::vec3& value) override; + + virtual const Transform getTransform(bool& success, int depth = 0) const override; + virtual const Transform getTransform() const override; + static const QString DEFAULT_COMPOUND_SHAPE_URL; QString getCompoundShapeURL() const; @@ -144,7 +150,6 @@ protected: // they aren't currently updated from data in the model/rig, and they don't have a direct effect // on what's rendered. ReadWriteLockable _jointDataLock; - ReadWriteLockable _modelScaleLock; bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations @@ -159,6 +164,7 @@ protected: int _lastKnownCurrentFrame{-1}; glm::u8vec3 _color; + glm::vec3 _modelScale; QString _modelURL; bool _relayParentJoints; bool _groupCulled { false }; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index b6fcd2f2ce..4229a4a152 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -263,6 +263,7 @@ enum class EntityVersion : PacketVersion { ShowKeyboardFocusHighlight, WebBillboardMode, ModelScale, + ReOrderParentIDProperties, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/physics/src/ObjectActionTractor.cpp b/libraries/physics/src/ObjectActionTractor.cpp index a46aac3f29..c7681e217c 100644 --- a/libraries/physics/src/ObjectActionTractor.cpp +++ b/libraries/physics/src/ObjectActionTractor.cpp @@ -60,7 +60,7 @@ bool ObjectActionTractor::getTarget(float deltaTimeStep, glm::quat& rotation, gl } if (other && otherIsReady) { bool success; - glm::vec3 otherWorldPosition = other->getWorldPosition(_otherJointIndex, success); + glm::vec3 otherWorldPosition = other->getJointWorldPosition(_otherJointIndex, success); if (!success) { linearTimeScale = FLT_MAX; angularTimeScale = FLT_MAX; diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h index be017a696d..a584bcd308 100644 --- a/libraries/shared/src/NestableTransformNode.h +++ b/libraries/shared/src/NestableTransformNode.h @@ -32,7 +32,7 @@ public: } bool success; - Transform jointWorldTransform = nestable->getTransform(_jointIndex, success); + Transform jointWorldTransform = nestable->getJointTransform(_jointIndex, success); if (!success) { return Transform(); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index e7bdc87bf3..d202afc59f 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -92,7 +92,7 @@ Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const return result; } if (parent) { - result = parent->getTransform(_parentJointIndex, success, depth + 1); + result = parent->getJointTransform(_parentJointIndex, success, depth + 1); if (getScalesWithParent()) { result.setScale(parent->scaleForChildren()); } @@ -203,7 +203,7 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, } if (parent) { - parentTransform = parent->getTransform(parentJointIndex, success); + parentTransform = parent->getJointTransform(parentJointIndex, success); if (!success) { return glm::vec3(0.0f); } @@ -240,7 +240,7 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, } if (parent) { - parentTransform = parent->getTransform(parentJointIndex, success); + parentTransform = parent->getJointTransform(parentJointIndex, success); if (!success) { return glm::quat(); } @@ -350,7 +350,7 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, } if (parent) { - parentTransform = parent->getTransform(parentJointIndex, success); + parentTransform = parent->getJointTransform(parentJointIndex, success); if (!success) { return glm::vec3(0.0f); } @@ -390,7 +390,7 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, } if (parent) { - parentTransform = parent->getTransform(parentJointIndex, success); + parentTransform = parent->getJointTransform(parentJointIndex, success); if (!success) { return glm::quat(); } @@ -525,8 +525,8 @@ glm::vec3 SpatiallyNestable::getWorldPosition() const { return result; } -glm::vec3 SpatiallyNestable::getWorldPosition(int jointIndex, bool& success) const { - return getTransform(jointIndex, success).getTranslation(); +glm::vec3 SpatiallyNestable::getJointWorldPosition(int jointIndex, bool& success) const { + return getJointTransform(jointIndex, success).getTranslation(); } void SpatiallyNestable::setWorldPosition(const glm::vec3& position, bool& success, bool tellPhysics) { @@ -579,7 +579,7 @@ glm::quat SpatiallyNestable::getWorldOrientation() const { } glm::quat SpatiallyNestable::getWorldOrientation(int jointIndex, bool& success) const { - return getTransform(jointIndex, success).getRotation(); + return getJointTransform(jointIndex, success).getRotation(); } void SpatiallyNestable::setWorldOrientation(const glm::quat& orientation, bool& success, bool tellPhysics) { @@ -765,7 +765,7 @@ void SpatiallyNestable::breakParentingLoop() const { } } -const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, int depth) const { +const Transform SpatiallyNestable::getJointTransform(int jointIndex, bool& success, int depth) const { // this returns the world-space transform for this object. It finds its parent's transform (which may // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform jointInWorldFrame; @@ -832,8 +832,8 @@ glm::vec3 SpatiallyNestable::getSNScale(bool& success) const { return getTransform(success).getScale(); } -glm::vec3 SpatiallyNestable::getSNScale(int jointIndex, bool& success) const { - return getTransform(jointIndex, success).getScale(); +glm::vec3 SpatiallyNestable::getJointSNScale(int jointIndex, bool& success) const { + return getJointTransform(jointIndex, success).getScale(); } void SpatiallyNestable::setSNScale(const glm::vec3& scale) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index a802a25e89..6b709f0352 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -129,9 +129,9 @@ public: virtual void setSNScale(const glm::vec3& scale, bool& success); // get world-frame values for a specific joint - virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const; - virtual glm::vec3 getWorldPosition(int jointIndex, bool& success) const; - virtual glm::vec3 getSNScale(int jointIndex, bool& success) const; + virtual const Transform getJointTransform(int jointIndex, bool& success, int depth = 0) const; + virtual glm::vec3 getJointWorldPosition(int jointIndex, bool& success) const; + virtual glm::vec3 getJointSNScale(int jointIndex, bool& success) const; // object's parent's frame virtual Transform getLocalTransform() const; diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index a78b9a17fc..7a1c37af33 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -458,6 +458,11 @@ void TabletProxy::emitWebEvent(const QVariant& msg) { } void TabletProxy::onTabletShown() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "onTabletShown"); + return; + } + if (_tabletShown) { Setting::Handle notificationSounds{ QStringLiteral("play_notification_sounds"), true}; Setting::Handle notificationSoundTablet{ QStringLiteral("play_notification_sounds_tablet"), true}; @@ -485,7 +490,11 @@ bool TabletProxy::isPathLoaded(const QVariant& path) { } void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) { - Q_ASSERT(QThread::currentThread() == qApp->thread()); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setQmlTabletRoot", Q_ARG(OffscreenQmlSurface*, qmlOffscreenSurface)); + return; + } + _qmlOffscreenSurface = qmlOffscreenSurface; _qmlTabletRoot = qmlOffscreenSurface ? qmlOffscreenSurface->getRootItem() : nullptr; if (_qmlTabletRoot && _qmlOffscreenSurface) { @@ -654,6 +663,11 @@ void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) { } void TabletProxy::stopQMLSource() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "stopQMLSource"); + return; + } + // For desktop toolbar mode dialogs. if (!_toolbarMode || !_desktopWindow) { qCDebug(uiLogging) << "tablet cannot clear QML because not desktop toolbar mode"; @@ -879,6 +893,12 @@ void TabletProxy::sendToQml(const QVariant& msg) { OffscreenQmlSurface* TabletProxy::getTabletSurface() { + if (QThread::currentThread() != thread()) { + OffscreenQmlSurface* result = nullptr; + BLOCKING_INVOKE_METHOD(this, "getTabletSurface", Q_RETURN_ARG(OffscreenQmlSurface*, result)); + return result; + } + return _qmlOffscreenSurface; } @@ -888,6 +908,11 @@ void TabletProxy::desktopWindowClosed() { } void TabletProxy::unfocus() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "unfocus"); + return; + } + if (_qmlOffscreenSurface) { _qmlOffscreenSurface->lowerKeyboard(); } diff --git a/scripts/system/away.js b/scripts/system/away.js index 45b6f43b73..3deb2249be 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -65,7 +65,7 @@ var eventMappingName = "io.highfidelity.away"; // goActive on hand controller bu var eventMapping = Controller.newMapping(eventMappingName); var avatarPosition = MyAvatar.position; var wasHmdMounted = HMD.mounted; - +var previousBubbleState = Users.getIgnoreRadiusEnabled(); // some intervals we may create/delete var avatarMovedInterval; @@ -166,7 +166,12 @@ function goAway(fromStartup) { avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL); }, WAIT_FOR_MOVE_ON_STARTUP); } - + + previousBubbleState = Users.getIgnoreRadiusEnabled(); + if (!previousBubbleState) { + Users.toggleIgnoreRadius(); + } + UserActivityLogger.bubbleToggled(Users.getIgnoreRadiusEnabled()); UserActivityLogger.toggledAway(true); MyAvatar.isAway = true; } @@ -179,6 +184,11 @@ function goActive() { UserActivityLogger.toggledAway(false); MyAvatar.isAway = false; + if (Users.getIgnoreRadiusEnabled() !== previousBubbleState) { + Users.toggleIgnoreRadius(); + UserActivityLogger.bubbleToggled(Users.getIgnoreRadiusEnabled()); + } + if (!Window.hasFocus()) { Window.setFocus(); } diff --git a/scripts/system/chat.js b/scripts/system/chat.js index b0a2e114a3..749665f3d8 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -45,6 +45,17 @@ var speechBubbleLineHeight = 0.05; // The height of a line of text in the speech bubble. var SPEECH_BUBBLE_MAX_WIDTH = 1; // meters + var textSizeOverlay = Overlays.addOverlay("text3d", { + position: MyAvatar.position, + lineHeight: speechBubbleLineHeight, + leftMargin: 0, + topMargin: 0, + rightMargin: 0, + bottomMargin: 0, + ignoreRayIntersection: true, + visible: false + }); + // Load the persistent variables from the Settings, with defaults. function loadSettings() { chatName = Settings.getValue('Chat_chatName', MyAvatar.displayName); @@ -63,6 +74,9 @@ speechBubbleOffset = Settings.getValue('Chat_speechBubbleOffset', {x: 0.0, y: 0.3, z:0.0}); speechBubbleJointName = Settings.getValue('Chat_speechBubbleJointName', 'Head'); speechBubbleLineHeight = Settings.getValue('Chat_speechBubbleLineHeight', 0.05); + Overlays.editOverlay(textSizeOverlay, { + lineHeight: speechBubbleLineHeight + }); saveSettings(); } @@ -637,7 +651,7 @@ // Only overlay text3d has a way to measure the text, not entities. // So we make a temporary one just for measuring text, then delete it. var speechBubbleTextOverlayID = Overlays.addOverlay("text3d", speechBubbleParams); - var textSize = Overlays.textSize(speechBubbleTextOverlayID, speechBubbleMessage); + var textSize = Overlays.textSize(textSizeOverlay, speechBubbleMessage); try { Overlays.deleteOverlay(speechBubbleTextOverlayID); } catch (e) {} @@ -971,6 +985,8 @@ unidentifyAvatars(); disconnectWebHandler(); + Overlays.deleteOverlay(textSizeOverlay); + if (onChatPage) { tablet.gotoHomeScreen(); onChatPage = false; diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index e59b2e35ad..5dcfee23cb 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -117,11 +117,12 @@ Script.include("/~/system/libraries/utils.js"); this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID; this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex; } - Overlays.editOverlay(this.grabbedThingID, reparentProps); // resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix if (HMD.tabletID && this.grabbedThingID === HMD.tabletID) { - resizeTablet(getTabletWidthFromSettings(), reparentProps.parentJointIndex); + reparentAndScaleTablet(getTabletWidthFromSettings(), reparentProps); + } else { + Entities.editEntity(this.grabbedThingID, reparentProps); } Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ @@ -140,7 +141,7 @@ Script.include("/~/system/libraries/utils.js"); }); } else if (!this.robbed){ // before we grabbed it, overlay was a child of something; put it back. - Overlays.editOverlay(this.grabbedThingID, { + Entities.editEntity(this.grabbedThingID, { parentID: this.previousParentID[this.grabbedThingID], parentJointIndex: this.previousParentJointIndex[this.grabbedThingID] }); diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index c0e3178521..c5ae9730f2 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -159,7 +159,7 @@ WebTablet = function (url, width, dpi, hand, location, visible) { url: url, localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET }, localRotation: Quat.angleAxis(180, Y_AXIS), - dimensions: {x: screenWidth, y: screenHeight, z: 0.1}, + dimensions: {x: screenWidth, y: screenHeight, z: 1.0}, dpi: tabletDpi, color: { red: 255, green: 255, blue: 255 }, alpha: 1.0, diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 931c346299..6f74b43a8e 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -395,7 +395,7 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) var tabletDpi = DEFAULT_DPI * (DEFAULT_WIDTH / tabletWidth); // update tablet model dimensions - Overlays.editOverlay(HMD.tabletID, { + Entities.editEntity(HMD.tabletID, { dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth } }); @@ -405,9 +405,9 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) var screenWidth = 0.9367 * tabletWidth; var screenHeight = 0.9000 * tabletHeight; var landscape = Tablet.getTablet("com.highfidelity.interface.tablet.system").landscape; - Overlays.editOverlay(HMD.tabletScreenID, { + Entities.editEntity(HMD.tabletScreenID, { localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET}, - dimensions: {x: landscape ? screenHeight : screenWidth, y: landscape ? screenWidth : screenHeight, z: 0.1}, + dimensions: {x: landscape ? screenHeight : screenWidth, y: landscape ? screenWidth : screenHeight, z: 1.0}, dpi: tabletDpi }); @@ -416,19 +416,83 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) var HOME_BUTTON_X_OFFSET = 0.00079 * sensorScaleOffsetOverride * sensorScaleFactor; var HOME_BUTTON_Y_OFFSET = -1 * ((tabletHeight / 2) - (4.0 * tabletScaleFactor / 2)) * sensorScaleOffsetOverride; var HOME_BUTTON_Z_OFFSET = (tabletDepth / 1.9) * sensorScaleOffsetOverride; - Overlays.editOverlay(HMD.homeButtonID, { + Entities.editEntity(HMD.homeButtonID, { localPosition: { x: HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET }, localRotation: { x: 0, y: 1, z: 0, w: 0 }, dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim } }); - Overlays.editOverlay(HMD.homeButtonHighlightID, { + Entities.editEntity(HMD.homeButtonHighlightID, { localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET }, localRotation: { x: 0, y: 1, z: 0, w: 0 }, dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim } }); }; + +reparentAndScaleTablet = function(width, reparentProps) { + + if (!HMD.tabletID || !HMD.tabletScreenID || !HMD.homeButtonID || !HMD.homeButtonHighlightID) { + return; + } + var sensorScaleFactor = MyAvatar.sensorToWorldScale; + var sensorScaleOffsetOverride = 1; + var SENSOR_TO_ROOM_MATRIX = 65534; + var parentJointIndex = reparentProps.parentJointIndex; + if (parentJointIndex === SENSOR_TO_ROOM_MATRIX) { + sensorScaleOffsetOverride = 1 / sensorScaleFactor; + } + + + // will need to be recaclulated if dimensions of fbx model change. + var TABLET_NATURAL_DIMENSIONS = {x: 32.083, y: 48.553, z: 2.269}; + var DEFAULT_DPI = 31; + var DEFAULT_WIDTH = 0.4375; + + // scale factor of natural tablet dimensions. + var tabletWidth = (width || DEFAULT_WIDTH) * sensorScaleFactor; + var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x; + var tabletHeight = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor; + var tabletDepth = TABLET_NATURAL_DIMENSIONS.z * tabletScaleFactor; + var tabletDpi = DEFAULT_DPI * (DEFAULT_WIDTH / tabletWidth); + + // update tablet model dimensions + + Entities.editEntity(HMD.tabletID, { + parentID: reparentProps.parentID, + parentJointIndex: reparentProps.parentJointIndex, + dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth} + }); + // update webOverlay + var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.5) * sensorScaleOffsetOverride; + var WEB_ENTITY_Y_OFFSET = 1.25 * tabletScaleFactor * sensorScaleOffsetOverride; + var screenWidth = 0.9367 * tabletWidth; + var screenHeight = 0.9000 * tabletHeight; + var landscape = Tablet.getTablet("com.highfidelity.interface.tablet.system").landscape; + Entities.editEntity(HMD.tabletScreenID, { + localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET}, + dimensions: {x: landscape ? screenHeight : screenWidth, y: landscape ? screenWidth : screenHeight, z: 1.0}, + dpi: tabletDpi + }); + + // update homeButton + var homeButtonDim = 4.0 * tabletScaleFactor / 1.5; + var HOME_BUTTON_X_OFFSET = 0.00079 * sensorScaleOffsetOverride * sensorScaleFactor; + var HOME_BUTTON_Y_OFFSET = -1 * ((tabletHeight / 2) - (4.0 * tabletScaleFactor / 2)) * sensorScaleOffsetOverride; + var HOME_BUTTON_Z_OFFSET = (tabletDepth / 1.9) * sensorScaleOffsetOverride; + Entities.editEntity(HMD.homeButtonID, { + localPosition: { x: HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET }, + localRotation: { x: 0, y: 1, z: 0, w: 0 }, + dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim } + }); + + Entities.editEntity(HMD.homeButtonHighlightID, { + localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET }, + localRotation: { x: 0, y: 1, z: 0, w: 0 }, + dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim } + }); +} + getMainTabletIDs = function () { var tabletIDs = []; if (HMD.tabletID) { diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6cda67db2d..b9ae635a4f 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -20,7 +20,7 @@ endfunction() if (BUILD_TOOLS) # Allow different tools for stable builds - if (RELEASE_TYPE STREQUAL "PRODUCTION") + if (STABLE_BUILD) set(ALL_TOOLS udt-test vhacd-util diff --git a/tools/nitpick/CMakeLists.txt b/tools/nitpick/CMakeLists.txt index e69b16b866..44eace5e70 100644 --- a/tools/nitpick/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -80,7 +80,9 @@ else () add_executable(${TARGET_NAME} ${NITPICK_SRCS} ${QM}) endif () -add_dependencies(${TARGET_NAME} resources) +if (NOT UNIX) + add_dependencies(${TARGET_NAME} resources) +endif() # disable /OPT:REF and /OPT:ICF for the Debug builds # This will prevent the following linker warnings