diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 94533137ad..8f2149f02d 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -21,6 +21,7 @@ const bool DEFAULT_IS_SOLID = false; const bool DEFAULT_IS_DASHED_LINE = false; Base3DOverlay::Base3DOverlay() : + SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()), _lineWidth(DEFAULT_LINE_WIDTH), _isSolid(DEFAULT_IS_SOLID), _isDashedLine(DEFAULT_IS_DASHED_LINE), @@ -31,15 +32,85 @@ Base3DOverlay::Base3DOverlay() : Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) : Overlay(base3DOverlay), - _transform(base3DOverlay->_transform), + SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()), _lineWidth(base3DOverlay->_lineWidth), _isSolid(base3DOverlay->_isSolid), _isDashedLine(base3DOverlay->_isDashedLine), _ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection), _drawInFront(base3DOverlay->_drawInFront) { + setTransform(base3DOverlay->getTransform()); } -void Base3DOverlay::setProperties(const QVariantMap& properties) { + +QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties) { + // the position and rotation in _transform are relative to the parent (aka local). The versions coming from + // scripts are in world-frame, unless localPosition or localRotation are used. Patch up the properties + // so that "position" and "rotation" are relative-to-parent values. + QVariantMap result = properties; + QUuid parentID = result["parentID"].isValid() ? QUuid(result["parentID"].toString()) : QUuid(); + int parentJointIndex = result["parentJointIndex"].isValid() ? result["parentJointIndex"].toInt() : -1; + bool success; + + // make "position" and "orientation" be relative-to-parent + if (result["localPosition"].isValid()) { + result["position"] = result["localPosition"]; + } else if (result["position"].isValid()) { + glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]), + parentID, parentJointIndex, success); + result["position"] = vec3toVariant(localPosition); + } + + if (result["localOrientation"].isValid()) { + result["orientation"] = result["localOrientation"]; + } else if (result["orientation"].isValid()) { + glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]), + parentID, parentJointIndex, success); + result["orientation"] = quatToVariant(localOrientation); + } + + return result; +} + +void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { + QVariantMap properties = originalProperties; + + // carry over some legacy keys + if (!properties["position"].isValid() && !properties["localPosition"].isValid()) { + if (properties["p1"].isValid()) { + properties["position"] = properties["p1"]; + } else if (properties["point"].isValid()) { + properties["position"] = properties["point"]; + } else if (properties["start"].isValid()) { + properties["position"] = properties["start"]; + } + } + if (!properties["orientation"].isValid() && properties["rotation"].isValid()) { + properties["orientation"] = properties["rotation"]; + } + if (!properties["localOrientation"].isValid() && properties["localRotation"].isValid()) { + properties["localOrientation"] = properties["localRotation"]; + } + + // All of parentID, parentJointIndex, position, orientation are needed to make sense of any of them. + // If any of these changed, pull any missing properties from the overlay. + if (properties["parentID"].isValid() || properties["parentJointIndex"].isValid() || + properties["position"].isValid() || properties["localPosition"].isValid() || + properties["orientation"].isValid() || properties["localOrientation"].isValid()) { + if (!properties["parentID"].isValid()) { + properties["parentID"] = getParentID(); + } + if (!properties["parentJointIndex"].isValid()) { + properties["parentJointIndex"] = getParentJointIndex(); + } + if (!properties["position"].isValid() && !properties["localPosition"].isValid()) { + properties["position"] = vec3toVariant(getPosition()); + } + if (!properties["orientation"].isValid() && !properties["localOrientation"].isValid()) { + properties["orientation"] = quatToVariant(getOrientation()); + } + } + + properties = convertOverlayLocationFromScriptSemantics(properties); Overlay::setProperties(properties); bool needRenderItemUpdate = false; @@ -52,17 +123,12 @@ void Base3DOverlay::setProperties(const QVariantMap& properties) { needRenderItemUpdate = true; } - auto position = properties["position"]; - - // if "position" property was not there, check to see if they included aliases: point, p1 - if (!position.isValid()) { - position = properties["p1"]; - if (!position.isValid()) { - position = properties["point"]; - } + if (properties["position"].isValid()) { + setLocalPosition(vec3FromVariant(properties["position"])); + needRenderItemUpdate = true; } - if (position.isValid()) { - setPosition(vec3FromVariant(position)); + if (properties["orientation"].isValid()) { + setLocalOrientation(quatFromVariant(properties["orientation"])); needRenderItemUpdate = true; } @@ -71,13 +137,6 @@ void Base3DOverlay::setProperties(const QVariantMap& properties) { needRenderItemUpdate = true; } - auto rotation = properties["rotation"]; - - if (rotation.isValid()) { - setRotation(quatFromVariant(rotation)); - needRenderItemUpdate = true; - } - if (properties["isSolid"].isValid()) { setIsSolid(properties["isSolid"].toBool()); } @@ -107,6 +166,15 @@ void Base3DOverlay::setProperties(const QVariantMap& properties) { setIgnoreRayIntersection(properties["ignoreRayIntersection"].toBool()); } + if (properties["parentID"].isValid()) { + setParentID(QUuid(properties["parentID"].toString())); + needRenderItemUpdate = true; + } + if (properties["parentJointIndex"].isValid()) { + setParentJointIndex(properties["parentJointIndex"].toInt()); + needRenderItemUpdate = true; + } + // Communicate changes to the renderItem if needed if (needRenderItemUpdate) { auto itemID = getRenderItemID(); @@ -123,12 +191,18 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "position" || property == "start" || property == "p1" || property == "point") { return vec3toVariant(getPosition()); } + if (property == "localPosition") { + return vec3toVariant(getLocalPosition()); + } + if (property == "rotation" || property == "orientation") { + return quatToVariant(getOrientation()); + } + if (property == "localRotation" || property == "localOrientation") { + return quatToVariant(getLocalOrientation()); + } if (property == "lineWidth") { return _lineWidth; } - if (property == "rotation") { - return quatToVariant(getRotation()); - } if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") { return _isSolid; } @@ -144,6 +218,12 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "drawInFront") { return _drawInFront; } + if (property == "parentID") { + return getParentID(); + } + if (property == "parentJointIndex") { + return getParentJointIndex(); + } return Overlay::getProperty(property); } @@ -152,3 +232,19 @@ bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3 float& distance, BoxFace& face, glm::vec3& surfaceNormal) { return false; } + +void Base3DOverlay::locationChanged(bool tellPhysics) { + auto itemID = getRenderItemID(); + if (render::Item::isValidID(itemID)) { + render::ScenePointer scene = qApp->getMain3DScene(); + render::PendingChanges pendingChanges; + pendingChanges.updateItem(itemID); + scene->enqueuePendingChanges(pendingChanges); + } + // Overlays can't currently have children. + // SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also +} + +void Base3DOverlay::parentDeleted() { + qApp->getOverlays().deleteOverlay(getOverlayID()); +} diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index e602dec48c..1860af4e85 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -12,10 +12,11 @@ #define hifi_Base3DOverlay_h #include +#include #include "Overlay.h" -class Base3DOverlay : public Overlay { +class Base3DOverlay : public Overlay, public SpatiallyNestable { Q_OBJECT public: @@ -24,12 +25,9 @@ public: // getters virtual bool is3D() const override { return true; } - const glm::vec3& getPosition() const { return _transform.getTranslation(); } - const glm::quat& getRotation() const { return _transform.getRotation(); } - const glm::vec3& getScale() const { return _transform.getScale(); } // TODO: consider implementing registration points in this class - const glm::vec3& getCenter() const { return getPosition(); } + glm::vec3 getCenter() const { return getPosition(); } float getLineWidth() const { return _lineWidth; } bool getIsSolid() const { return _isSolid; } @@ -38,12 +36,6 @@ public: bool getIgnoreRayIntersection() const { return _ignoreRayIntersection; } bool getDrawInFront() const { return _drawInFront; } - // setters - void setPosition(const glm::vec3& value) { _transform.setTranslation(value); } - void setRotation(const glm::quat& value) { _transform.setRotation(value); } - void setScale(float value) { _transform.setScale(value); } - void setScale(const glm::vec3& value) { _transform.setScale(value); } - void setLineWidth(float lineWidth) { _lineWidth = lineWidth; } void setIsSolid(bool isSolid) { _isSolid = isSolid; } void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; } @@ -64,7 +56,8 @@ public: } protected: - Transform _transform; + virtual void locationChanged(bool tellPhysics = true) override; + virtual void parentDeleted() override; float _lineWidth; bool _isSolid; diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 6ebfd5c71c..e9ee997aac 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -69,17 +69,17 @@ void Circle3DOverlay::render(RenderArgs* args) { // FIXME: THe line width of _lineWidth is not supported anymore, we ll need a workaround - auto transform = _transform; + auto transform = getTransform(); transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch.setModelTransform(transform); - + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getIsSolid()) { if (!_quadVerticesID) { _quadVerticesID = geometryCache->allocateID(); } - + if (geometryChanged) { QVector points; QVector colors; diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index d59e552779..a384c992ad 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -37,7 +37,11 @@ Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : } void Image3DOverlay::update(float deltatime) { - applyTransformTo(_transform); + if (usecTimestampNow() > _transformExpiry) { + Transform transform = getTransform(); + applyTransformTo(transform); + setTransform(transform); + } } void Image3DOverlay::render(RenderArgs* args) { @@ -86,13 +90,14 @@ void Image3DOverlay::render(RenderArgs* args) { xColor color = getColor(); float alpha = getAlpha(); - applyTransformTo(_transform, true); - Transform transform = _transform; + Transform transform = getTransform(); + applyTransformTo(transform, true); + setTransform(transform); transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - + DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) @@ -187,7 +192,10 @@ bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec float& distance, BoxFace& face, glm::vec3& surfaceNormal) { if (_texture && _texture->isLoaded()) { // Make sure position and rotation is updated. - applyTransformTo(_transform, true); + Transform transform = getTransform(); + // XXX this code runs too often for this... + // applyTransformTo(transform, true); + // setTransform(transform); // Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale. bool isNull = _fromImage.isNull(); @@ -197,7 +205,10 @@ bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec glm::vec2 dimensions = _dimensions * glm::vec2(width / maxSize, height / maxSize); // FIXME - face and surfaceNormal not being set - return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), dimensions, distance); + return findRayRectangleIntersection(origin, direction, + transform.getRotation(), + transform.getTranslation(), + dimensions, distance); } return false; diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index a05783fea2..6b46b5b884 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -35,8 +35,8 @@ AABox Line3DOverlay::getBounds() const { auto extents = Extents{}; extents.addPoint(_start); extents.addPoint(_end); - extents.transform(_transform); - + extents.transform(getTransform()); + return AABox(extents); } @@ -52,7 +52,7 @@ void Line3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { - batch->setModelTransform(_transform); + batch->setModelTransform(getTransform()); auto geometryCache = DependencyManager::get(); if (getIsDashedLine()) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 9c203c0129..0a89268f6b 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -178,3 +178,12 @@ bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const g ModelOverlay* ModelOverlay::createClone() const { return new ModelOverlay(this); } + +void ModelOverlay::locationChanged(bool tellPhysics) { + Base3DOverlay::locationChanged(tellPhysics); + + if (_model && _model->isActive()) { + _model->setRotation(getRotation()); + _model->setTranslation(getPosition()); + } +} diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 091cab44c9..d5f709c2db 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -39,6 +39,8 @@ public: virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + void locationChanged(bool tellPhysics) override; + private: ModelPointer _model; diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 5d2c315a92..82b90d228c 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -77,7 +77,7 @@ void Overlay::setProperties(const QVariantMap& properties) { if (properties["pulsePeriod"].isValid()) { setPulsePeriod(properties["pulsePeriod"].toFloat()); } - + if (properties["alphaPulse"].isValid()) { setAlphaPulse(properties["alphaPulse"].toFloat()); } @@ -90,7 +90,7 @@ void Overlay::setProperties(const QVariantMap& properties) { bool visible = properties["visible"].toBool(); setVisible(visible); } - + if (properties["anchor"].isValid()) { QString property = properties["anchor"].toString(); if (property == "MyAvatar") { diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 466ec0e913..51792b24b3 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -17,7 +17,7 @@ class Overlay : public QObject { Q_OBJECT - + public: enum Anchor { NO_ANCHOR, @@ -31,9 +31,13 @@ public: Overlay(); Overlay(const Overlay* overlay); ~Overlay(); + + unsigned int getOverlayID() { return _overlayID; } + void setOverlayID(unsigned int overlayID) { _overlayID = overlayID; } + virtual void update(float deltatime) {} virtual void render(RenderArgs* args) = 0; - + virtual AABox getBounds() const = 0; virtual bool supportsGetProperty() const { return true; } @@ -85,6 +89,8 @@ protected: render::ItemID _renderItemID{ render::Item::INVALID_ITEM_ID }; + unsigned int _overlayID; // what Overlays.cpp knows this instance as + bool _isLoaded; float _alpha; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 0b4bcc8652..2c1f7552cd 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -192,6 +192,7 @@ unsigned int Overlays::addOverlay(const QString& type, const QVariant& propertie unsigned int Overlays::addOverlay(Overlay::Pointer overlay) { QWriteLocker lock(&_lock); unsigned int thisID = _nextOverlayID; + overlay->setOverlayID(thisID); _nextOverlayID++; if (overlay->is3D()) { _overlaysWorld[thisID] = overlay; diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index c580464e16..58d72b100b 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -28,10 +28,10 @@ Planar3DOverlay::Planar3DOverlay(const Planar3DOverlay* planar3DOverlay) : AABox Planar3DOverlay::getBounds() const { auto halfDimensions = glm::vec3{_dimensions / 2.0f, 0.01f}; - + auto extents = Extents{-halfDimensions, halfDimensions}; - extents.transform(_transform); - + extents.transform(getTransform()); + return AABox(extents); } diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 774237d334..07c2861f16 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -39,7 +39,7 @@ void Sphere3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { - Transform transform = _transform; + Transform transform = getTransform(); transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE); batch->setModelTransform(transform); diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 0ae1c306ba..153f787fc7 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -65,44 +65,49 @@ xColor Text3DOverlay::getBackgroundColor() { } void Text3DOverlay::update(float deltatime) { - applyTransformTo(_transform); + if (usecTimestampNow() > _transformExpiry) { + Transform transform = getTransform(); + applyTransformTo(transform); + setTransform(transform); + } } void Text3DOverlay::render(RenderArgs* args) { if (!_visible || !getParentVisible()) { return; // do nothing if we're not visible } - + Q_ASSERT(args->_batch); auto& batch = *args->_batch; - - applyTransformTo(_transform, true); - batch.setModelTransform(_transform); + + Transform transform = getTransform(); + applyTransformTo(transform, true); + setTransform(transform); + batch.setModelTransform(transform); const float MAX_COLOR = 255.0f; xColor backgroundColor = getBackgroundColor(); glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, getBackgroundAlpha()); - + glm::vec2 dimensions = getDimensions(); glm::vec2 halfDimensions = dimensions * 0.5f; - + const float SLIGHTLY_BEHIND = -0.001f; - + glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND); glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); - + // Same font properties as textSize() float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO; - + float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight; - + glm::vec2 clipMinimum(0.0f, 0.0f); glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor, (dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor); - Transform transform = _transform; transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin), halfDimensions.y - _topMargin, 0.001f)); transform.setScale(scaleFactor); @@ -222,6 +227,8 @@ QSizeF Text3DOverlay::textSize(const QString& text) const { bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance, BoxFace &face, glm::vec3& surfaceNormal) { - applyTransformTo(_transform, true); + Transform transform = getTransform(); + applyTransformTo(transform, true); + setTransform(transform); return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal); } diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index 563198c976..ad61e28bc7 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -56,7 +56,7 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve float& distance, BoxFace& face, glm::vec3& surfaceNormal) { // extents is the entity relative, scaled, centered extents of the entity glm::mat4 worldToEntityMatrix; - _transform.getInverseMatrix(worldToEntityMatrix); + getTransform().getInverseMatrix(worldToEntityMatrix); glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); glm::vec3 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 1c84e71fa7..6ca3e49569 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -47,7 +47,7 @@ Web3DOverlay::~Web3DOverlay() { _webSurface->disconnect(_connection); // The lifetime of the QML surface MUST be managed by the main thread // Additionally, we MUST use local variables copied by value, rather than - // member variables, since they would implicitly refer to a this that + // member variables, since they would implicitly refer to a this that // is no longer valid auto webSurface = _webSurface; AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] { @@ -57,7 +57,11 @@ Web3DOverlay::~Web3DOverlay() { } void Web3DOverlay::update(float deltatime) { - applyTransformTo(_transform); + if (usecTimestampNow() > _transformExpiry) { + Transform transform = getTransform(); + applyTransformTo(transform); + setTransform(transform); + } } void Web3DOverlay::render(RenderArgs* args) { @@ -85,8 +89,9 @@ void Web3DOverlay::render(RenderArgs* args) { vec2 halfSize = size / 2.0f; vec4 color(toGlm(getColor()), getAlpha()); - applyTransformTo(_transform, true); - Transform transform = _transform; + Transform transform = getTransform(); + applyTransformTo(transform, true); + setTransform(transform); if (glm::length2(getDimensions()) != 1.0f) { transform.postScale(vec3(getDimensions(), 1.0f)); } @@ -165,7 +170,10 @@ bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& // FIXME - face and surfaceNormal not being returned // Make sure position and rotation is updated. - applyTransformTo(_transform, true); + Transform transform; + applyTransformTo(transform, true); + setTransform(transform); + vec2 size = _resolution / _dpi * INCHES_TO_METERS * vec2(getDimensions()); // Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale. return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), size, distance); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f12075d191..3677a0bbc8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -322,10 +322,6 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } - // these are only needed because the names don't match - virtual const glm::quat getRotation() const { return getOrientation(); } - virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } - // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 2a3cb4af47..c3dbafa0d9 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -26,6 +26,12 @@ SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : _transform.setRotation(glm::quat()); } +SpatiallyNestable::~SpatiallyNestable() { + forEachChild([&](SpatiallyNestablePointer object) { + object->parentDeleted(); + }); +} + const QUuid SpatiallyNestable::getID() const { QUuid result; _idLock.withReadLock([&] { @@ -35,6 +41,10 @@ const QUuid SpatiallyNestable::getID() const { } void SpatiallyNestable::setID(const QUuid& id) { + // adjust the parentID of any children + forEachChild([&](SpatiallyNestablePointer object) { + object->setParentID(id); + }); _idLock.withWriteLock([&] { _id = id; }); @@ -313,17 +323,20 @@ void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success, bo success = false; return; } + + bool changed = false; Transform parentTransform = getParentTransform(success); Transform myWorldTransform; _transformLock.withWriteLock([&] { Transform::mult(myWorldTransform, parentTransform, _transform); - myWorldTransform.setTranslation(position); - Transform::inverseMult(_transform, parentTransform, myWorldTransform); + if (myWorldTransform.getTranslation() != position) { + changed = true; + myWorldTransform.setTranslation(position); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + } }); - if (success) { + if (success && changed) { locationChanged(tellPhysics); - } else { - qDebug() << "setPosition failed for" << getID(); } } @@ -363,14 +376,18 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& succe return; } + bool changed = false; Transform parentTransform = getParentTransform(success); Transform myWorldTransform; _transformLock.withWriteLock([&] { Transform::mult(myWorldTransform, parentTransform, _transform); - myWorldTransform.setRotation(orientation); - Transform::inverseMult(_transform, parentTransform, myWorldTransform); + if (myWorldTransform.getRotation() != orientation) { + changed = true; + myWorldTransform.setRotation(orientation); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + } }); - if (success) { + if (success && changed) { locationChanged(tellPhysics); } } @@ -513,6 +530,15 @@ const Transform SpatiallyNestable::getTransform(bool& success, int depth) const return result; } +const Transform SpatiallyNestable::getTransform() const { + bool success; + Transform result = getTransform(success); + if (!success) { + qDebug() << "getTransform failed for" << getID(); + } + return result; +} + const Transform SpatiallyNestable::getTransform(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. @@ -549,15 +575,27 @@ void SpatiallyNestable::setTransform(const Transform& transform, bool& success) success = false; return; } + + bool changed = false; Transform parentTransform = getParentTransform(success); _transformLock.withWriteLock([&] { + Transform beforeTransform = _transform; Transform::inverseMult(_transform, parentTransform, transform); + if (_transform != beforeTransform) { + changed = true; + } }); - if (success) { + if (success && changed) { locationChanged(); } } +bool SpatiallyNestable::setTransform(const Transform& transform) { + bool success; + setTransform(transform, success); + return success; +} + glm::vec3 SpatiallyNestable::getScale() const { // TODO: scale glm::vec3 result; @@ -575,14 +613,43 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { void SpatiallyNestable::setScale(const glm::vec3& scale) { // guard against introducing NaN into the transform if (isNaN(scale)) { - qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; + qDebug() << "SpatiallyNestable::setScale -- scale contains NaN"; return; } + + bool changed = false; // TODO: scale _transformLock.withWriteLock([&] { - _transform.setScale(scale); + if (_transform.getScale() != scale) { + _transform.setScale(scale); + changed = true; + } }); - dimensionsChanged(); + if (changed) { + dimensionsChanged(); + } +} + +void SpatiallyNestable::setScale(float value) { + // guard against introducing NaN into the transform + if (value <= 0.0f) { + qDebug() << "SpatiallyNestable::setScale -- scale is zero or negative value"; + return; + } + + bool changed = false; + // TODO: scale + _transformLock.withWriteLock([&] { + glm::vec3 beforeScale = _transform.getScale(); + _transform.setScale(value); + if (_transform.getScale() != beforeScale) { + changed = true; + } + }); + + if (changed) { + dimensionsChanged(); + } } const Transform SpatiallyNestable::getLocalTransform() const { @@ -599,10 +666,18 @@ void SpatiallyNestable::setLocalTransform(const Transform& transform) { qDebug() << "SpatiallyNestable::setLocalTransform -- transform contains NaN"; return; } + + bool changed = false; _transformLock.withWriteLock([&] { - _transform = transform; + if (_transform != transform) { + _transform = transform; + changed = true; + } }); - locationChanged(); + + if (changed) { + locationChanged(); + } } glm::vec3 SpatiallyNestable::getLocalPosition() const { @@ -619,10 +694,16 @@ void SpatiallyNestable::setLocalPosition(const glm::vec3& position, bool tellPhy qDebug() << "SpatiallyNestable::setLocalPosition -- position contains NaN"; return; } + bool changed = false; _transformLock.withWriteLock([&] { - _transform.setTranslation(position); + if (_transform.getTranslation() != position) { + _transform.setTranslation(position); + changed = true; + } }); - locationChanged(tellPhysics); + if (changed) { + locationChanged(tellPhysics); + } } glm::quat SpatiallyNestable::getLocalOrientation() const { @@ -639,10 +720,16 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { qDebug() << "SpatiallyNestable::setLocalOrientation -- orientation contains NaN"; return; } + bool changed = false; _transformLock.withWriteLock([&] { - _transform.setRotation(orientation); + if (_transform.getRotation() != orientation) { + _transform.setRotation(orientation); + changed = true; + } }); - locationChanged(); + if (changed) { + locationChanged(); + } } glm::vec3 SpatiallyNestable::getLocalVelocity() const { @@ -688,9 +775,14 @@ void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } + + bool changed = false; // TODO: scale _transformLock.withWriteLock([&] { - _transform.setScale(scale); + if (_transform.getScale() != scale) { + _transform.setScale(scale); + changed = true; + } }); dimensionsChanged(); } @@ -886,12 +978,18 @@ void SpatiallyNestable::getLocalTransformAndVelocities( } void SpatiallyNestable::setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity) { + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity) { + + bool changed = false; + // transform _transformLock.withWriteLock([&] { - _transform = localTransform; + if (_transform != localTransform) { + _transform = localTransform; + changed = true; + } }); // linear velocity _velocityLock.withWriteLock([&] { @@ -901,5 +999,8 @@ void SpatiallyNestable::setLocalTransformAndVelocities( _angularVelocityLock.withWriteLock([&] { _angularVelocity = localAngularVelocity; }); - locationChanged(false); + + if (changed) { + locationChanged(false); + } } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index c2563a1188..391f13cc27 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -28,13 +28,14 @@ using SpatiallyNestableConstPointer = std::shared_ptr; enum class NestableType { Entity, - Avatar + Avatar, + Overlay }; class SpatiallyNestable : public std::enable_shared_from_this { public: SpatiallyNestable(NestableType nestableType, QUuid id); - virtual ~SpatiallyNestable() { } + virtual ~SpatiallyNestable(); virtual const QUuid getID() const; virtual void setID(const QUuid& id); @@ -53,7 +54,9 @@ public: // world frame virtual const Transform getTransform(bool& success, int depth = 0) const; + virtual const Transform getTransform() const; virtual void setTransform(const Transform& transform, bool& success); + virtual bool setTransform(const Transform& transform); virtual Transform getParentTransform(bool& success, int depth = 0) const; @@ -68,6 +71,10 @@ public: virtual void setOrientation(const glm::quat& orientation, bool& success, bool tellPhysics = true); virtual void setOrientation(const glm::quat& orientation); + // these are here because some older code uses rotation rather than orientation + virtual const glm::quat getRotation() const { return getOrientation(); } + virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } + virtual glm::vec3 getVelocity(bool& success) const; virtual glm::vec3 getVelocity() const; virtual void setVelocity(const glm::vec3& velocity, bool& success); @@ -91,6 +98,7 @@ public: virtual glm::vec3 getScale() const; virtual void setScale(const glm::vec3& scale); + virtual void setScale(float value); // get world-frame values for a specific joint virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const; @@ -123,10 +131,10 @@ public: // this object's frame virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const; - virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const = 0; - virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const = 0; - virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) = 0; - virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) = 0; + virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { return glm::quat(); } + virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { return glm::vec3(); } + virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { return false; } + virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {return false; } SpatiallyNestablePointer getThisPointer() const; @@ -170,6 +178,7 @@ protected: virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed virtual void dimensionsChanged() { } // called when a this object's dimensions have changed + virtual void parentDeleted() { } // called on children of a deleted parent // _queryAACube is used to decide where something lives in the octree mutable AACube _queryAACube; diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 1e1d10c54b..38d47695f7 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -89,6 +89,10 @@ public: return _rotation == other._rotation && _scale == other._scale && _translation == other._translation; } + bool operator!=(const Transform& other) const { + return _rotation != other._rotation || _scale != other._scale || _translation != other._translation; + } + Transform& setIdentity(); const Vec3& getTranslation() const;