From 3167d3c0c726f791fff2d3c3041618e3032cd57a Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 23 Aug 2018 14:05:44 -0700 Subject: [PATCH 01/23] Create TransformNodes for SpatiallyNestables, the mouse, and MyAvatar head --- .../src/avatar/MyAvatarHeadTransformNode.cpp | 23 ++++++++++ .../src/avatar/MyAvatarHeadTransformNode.h | 19 ++++++++ interface/src/raypick/MouseTransformNode.cpp | 43 +++++++++++++++++++ interface/src/raypick/MouseTransformNode.h | 23 ++++++++++ .../shared/src/NestableTransformNode.cpp | 31 +++++++++++++ libraries/shared/src/NestableTransformNode.h | 25 +++++++++++ libraries/shared/src/TransformNode.h | 18 ++++++++ 7 files changed, 182 insertions(+) create mode 100644 interface/src/avatar/MyAvatarHeadTransformNode.cpp create mode 100644 interface/src/avatar/MyAvatarHeadTransformNode.h create mode 100644 interface/src/raypick/MouseTransformNode.cpp create mode 100644 interface/src/raypick/MouseTransformNode.h create mode 100644 libraries/shared/src/NestableTransformNode.cpp create mode 100644 libraries/shared/src/NestableTransformNode.h create mode 100644 libraries/shared/src/TransformNode.h diff --git a/interface/src/avatar/MyAvatarHeadTransformNode.cpp b/interface/src/avatar/MyAvatarHeadTransformNode.cpp new file mode 100644 index 0000000000..82c2f8b703 --- /dev/null +++ b/interface/src/avatar/MyAvatarHeadTransformNode.cpp @@ -0,0 +1,23 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MyAvatarHeadTransformNode.h" + +#include "DependencyManager.h" +#include "AvatarManager.h" +#include "MyAvatar.h" + +Transform MyAvatarHeadTransformNode::getTransform() { + auto myAvatar = DependencyManager::get()->getMyAvatar(); + + glm::vec3 pos = myAvatar->getHeadPosition(); + glm::quat headOri = myAvatar->getHeadOrientation(); + glm::quat ori = headOri * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT); + + return Transform(ori, myAvatar->scaleForChildren(), pos); +} \ No newline at end of file diff --git a/interface/src/avatar/MyAvatarHeadTransformNode.h b/interface/src/avatar/MyAvatarHeadTransformNode.h new file mode 100644 index 0000000000..a7d7144521 --- /dev/null +++ b/interface/src/avatar/MyAvatarHeadTransformNode.h @@ -0,0 +1,19 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_MyAvatarHeadTransformNode_h +#define hifi_MyAvatarHeadTransformNode_h + +#include "TransformNode.h" + +class MyAvatarHeadTransformNode : public TransformNode { +public: + MyAvatarHeadTransformNode() { } + Transform getTransform() override; +}; + +#endif // hifi_MyAvatarHeadTransformNode_h \ No newline at end of file diff --git a/interface/src/raypick/MouseTransformNode.cpp b/interface/src/raypick/MouseTransformNode.cpp new file mode 100644 index 0000000000..4bc85ae69a --- /dev/null +++ b/interface/src/raypick/MouseTransformNode.cpp @@ -0,0 +1,43 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MouseTransformNode.h" + +#include "DependencyManager.h" +#include "PickManager.h" +#include "MouseRayPick.h" + +const PickFilter MOUSE_TRANSFORM_NODE_PICK_FILTER( + 1 << PickFilter::PICK_ENTITIES | + 1 << PickFilter::PICK_AVATARS | + 1 << PickFilter::PICK_INCLUDE_NONCOLLIDABLE +); +const float MOUSE_TRANSFORM_NODE_MAX_DISTANCE = 1000.0f; + +MouseTransformNode::MouseTransformNode() { + _parentMouseRayPick = DependencyManager::get()->addPick(PickQuery::Ray, + std::make_shared(MOUSE_TRANSFORM_NODE_PICK_FILTER, MOUSE_TRANSFORM_NODE_MAX_DISTANCE, true)); +} + +MouseTransformNode::~MouseTransformNode() { + if (DependencyManager::isSet()) { + auto pickManager = DependencyManager::get(); + if (pickManager) { + pickManager->removePick(_parentMouseRayPick); + } + } +} + +Transform MouseTransformNode::getTransform() { + Transform transform; + std::shared_ptr rayPickResult = DependencyManager::get()->getPrevPickResultTyped(_parentMouseRayPick); + if (rayPickResult) { + transform.setTranslation(rayPickResult->intersection); + } + return transform; +} \ No newline at end of file diff --git a/interface/src/raypick/MouseTransformNode.h b/interface/src/raypick/MouseTransformNode.h new file mode 100644 index 0000000000..7a05370dd7 --- /dev/null +++ b/interface/src/raypick/MouseTransformNode.h @@ -0,0 +1,23 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_MouseTransformNode_h +#define hifi_MouseTransformNode_h + +#include "TransformNode.h" + +class MouseTransformNode : public TransformNode { +public: + MouseTransformNode(); + ~MouseTransformNode(); + Transform getTransform() override; + +protected: + unsigned int _parentMouseRayPick = 0; +}; + +#endif // hifi_MouseTransformNode_h \ No newline at end of file diff --git a/libraries/shared/src/NestableTransformNode.cpp b/libraries/shared/src/NestableTransformNode.cpp new file mode 100644 index 0000000000..7fb7187aee --- /dev/null +++ b/libraries/shared/src/NestableTransformNode.cpp @@ -0,0 +1,31 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "NestableTransformNode.h" + +NestableTransformNode::NestableTransformNode(SpatiallyNestableWeakPointer spatiallyNestable, int jointIndex) : + _spatiallyNestable(spatiallyNestable), + _jointIndex(jointIndex) +{ +} + +Transform NestableTransformNode::getTransform() { + auto nestable = _spatiallyNestable.lock(); + if (!nestable) { + return Transform(); + } + + bool success; + Transform jointWorldTransform = nestable->getTransform(_jointIndex, success, 30); + + if (success) { + return jointWorldTransform; + } else { + return Transform(); + } +} \ No newline at end of file diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h new file mode 100644 index 0000000000..131de9e786 --- /dev/null +++ b/libraries/shared/src/NestableTransformNode.h @@ -0,0 +1,25 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_NestableTransformNode_h +#define hifi_NestableTransformNode_h + +#include "TransformNode.h" + +#include "SpatiallyNestable.h" + +class NestableTransformNode : public TransformNode { +public: + NestableTransformNode(SpatiallyNestableWeakPointer spatiallyNestable, int jointIndex); + Transform getTransform() override; + +protected: + SpatiallyNestableWeakPointer _spatiallyNestable; + int _jointIndex; +}; + +#endif // hifi_NestableTransformNode_h \ No newline at end of file diff --git a/libraries/shared/src/TransformNode.h b/libraries/shared/src/TransformNode.h new file mode 100644 index 0000000000..73223a8cee --- /dev/null +++ b/libraries/shared/src/TransformNode.h @@ -0,0 +1,18 @@ +// +// Created by Sabrina Shanman 8/14/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_TransformNode_h +#define hifi_TransformNode_h + +#include "Transform.h" + +class TransformNode { +public: + virtual Transform getTransform() = 0; +}; + +#endif // hifi_TransformNode_h \ No newline at end of file From b0f8d3e42727e77a79a3e8eee8da507701828d25 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 23 Aug 2018 14:06:39 -0700 Subject: [PATCH 02/23] Add PickTransformNode --- libraries/pointers/src/Pick.h | 1 + libraries/pointers/src/PickManager.cpp | 8 ++++++ libraries/pointers/src/PickManager.h | 2 ++ libraries/pointers/src/PickTransformNode.cpp | 26 ++++++++++++++++++++ libraries/pointers/src/PickTransformNode.h | 22 +++++++++++++++++ 5 files changed, 59 insertions(+) create mode 100644 libraries/pointers/src/PickTransformNode.cpp create mode 100644 libraries/pointers/src/PickTransformNode.h diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h index fc09064bd1..1a48aac0ef 100644 --- a/libraries/pointers/src/Pick.h +++ b/libraries/pointers/src/Pick.h @@ -17,6 +17,7 @@ #include #include +#include enum IntersectionType { NONE = 0, diff --git a/libraries/pointers/src/PickManager.cpp b/libraries/pointers/src/PickManager.cpp index 470d88a46c..b7c57c6aba 100644 --- a/libraries/pointers/src/PickManager.cpp +++ b/libraries/pointers/src/PickManager.cpp @@ -88,6 +88,14 @@ void PickManager::setIncludeItems(unsigned int uid, const QVector& includ } } +Transform PickManager::getResultTransform(unsigned int uid) const { + auto pick = findPick(uid); + if (pick) { + return pick->getResultTransform(); + } + return Transform(); +} + void PickManager::update() { uint64_t expiry = usecTimestampNow() + _perFrameTimeBudget; std::unordered_map>> cachedPicks; diff --git a/libraries/pointers/src/PickManager.h b/libraries/pointers/src/PickManager.h index 242550d837..3209a4c037 100644 --- a/libraries/pointers/src/PickManager.h +++ b/libraries/pointers/src/PickManager.h @@ -40,6 +40,8 @@ public: void setIgnoreItems(unsigned int uid, const QVector& ignore) const; void setIncludeItems(unsigned int uid, const QVector& include) const; + Transform getResultTransform(unsigned int uid) const; + bool isLeftHand(unsigned int uid); bool isRightHand(unsigned int uid); bool isMouse(unsigned int uid); diff --git a/libraries/pointers/src/PickTransformNode.cpp b/libraries/pointers/src/PickTransformNode.cpp new file mode 100644 index 0000000000..fe011b7fcd --- /dev/null +++ b/libraries/pointers/src/PickTransformNode.cpp @@ -0,0 +1,26 @@ +// +// Created by Sabrina Shanman 8/22/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "PickTransformNode.h" + +#include "DependencyManager.h" +#include "PickManager.h" + +PickTransformNode::PickTransformNode(unsigned int uid) : + _uid(uid) +{ +} + +Transform PickTransformNode::getTransform() { + auto pickManager = DependencyManager::get(); + if (!pickManager) { + return Transform(); + } + + return pickManager->getResultTransform(_uid); +} \ No newline at end of file diff --git a/libraries/pointers/src/PickTransformNode.h b/libraries/pointers/src/PickTransformNode.h new file mode 100644 index 0000000000..7547d3f181 --- /dev/null +++ b/libraries/pointers/src/PickTransformNode.h @@ -0,0 +1,22 @@ +// +// Created by Sabrina Shanman 8/22/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_PickTransformNode_h +#define hifi_PickTransformNode_h + +#include "TransformNode.h" + +class PickTransformNode : public TransformNode { +public: + PickTransformNode(unsigned int uid); + Transform getTransform() override; + +protected: + unsigned int _uid; +}; + +#endif // hifi_PickTransformNode_h \ No newline at end of file From 68b86963d4c616413279f21a5ec2adf2845f4580 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 22 Aug 2018 15:27:28 -0700 Subject: [PATCH 03/23] Add CollisionRegion copy constructor --- libraries/shared/src/RegisteredMetaTypes.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index e78dbafd75..3c8ee2ed7d 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -264,6 +264,18 @@ public: class CollisionRegion : public MathPick { public: CollisionRegion() { } + + CollisionRegion(const CollisionRegion& collisionRegion) : + modelURL(collisionRegion.modelURL), + shapeInfo(std::make_shared()), + transform(collisionRegion.transform), + parentID(collisionRegion.parentID), + parentJointIndex(collisionRegion.parentJointIndex), + joint(collisionRegion.joint) + { + shapeInfo->setParams(collisionRegion.shapeInfo->getType(), collisionRegion.shapeInfo->getHalfExtents(), collisionRegion.modelURL.toString()); + } + CollisionRegion(const QVariantMap& pickVariant) { if (pickVariant["shape"].isValid()) { auto shape = pickVariant["shape"].toMap(); From 6e160ad22f790a1b91e19cb1c6d7753c2cb40f48 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 16 Aug 2018 11:32:07 -0700 Subject: [PATCH 04/23] Add TransformNode-based parenting and implement for CollisionPicks --- interface/src/raypick/CollisionPick.cpp | 57 ++++++++++++++++--- interface/src/raypick/CollisionPick.h | 24 ++++---- interface/src/raypick/ParabolaPick.cpp | 12 ++++ interface/src/raypick/ParabolaPick.h | 1 + .../src/raypick/PickScriptingInterface.cpp | 50 +++++++++++++++- .../src/raypick/PickScriptingInterface.h | 3 + interface/src/raypick/RayPick.cpp | 12 ++++ interface/src/raypick/RayPick.h | 1 + interface/src/raypick/StylusPick.cpp | 12 ++++ interface/src/raypick/StylusPick.h | 1 + libraries/pointers/src/Pick.h | 6 +- libraries/shared/src/RegisteredMetaTypes.h | 29 +++++++++- 12 files changed, 184 insertions(+), 24 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 9f2e6da2e8..8c3d28fdfd 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -86,7 +86,7 @@ QVariantMap CollisionPickResult::toVariantMap() const { return variantMap; } -bool CollisionPick::isShapeInfoReady() { +bool CollisionPick::getShapeInfoReady() { if (_mathPick.shouldComputeShapeInfo()) { if (_cachedResource && _cachedResource->isLoaded()) { computeShapeInfo(_mathPick, *_mathPick.shapeInfo, _cachedResource); @@ -95,8 +95,23 @@ bool CollisionPick::isShapeInfoReady() { return false; } + else { + computeShapeInfoDimensionsOnly(_mathPick, *_mathPick.shapeInfo, _cachedResource); + return true; + } +} - return true; +void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { + ShapeType type = shapeInfo.getType(); + glm::vec3 dimensions = pick.transform.getScale(); + QString modelURL = (resource ? resource->getURL().toString() : ""); + if (type == SHAPE_TYPE_COMPOUND) { + shapeInfo.setParams(type, dimensions, modelURL); + } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { + shapeInfo.setParams(type, 0.5f * dimensions, modelURL); + } else { + shapeInfo.setParams(type, 0.5f * dimensions, modelURL); + } } void CollisionPick::computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { @@ -328,8 +343,23 @@ void CollisionPick::computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo } } +CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine) : + Pick(filter, maxDistance, enabled), + _mathPick(collisionRegion), + _physicsEngine(physicsEngine) { + if (collisionRegion.shouldComputeShapeInfo()) { + _cachedResource = DependencyManager::get()->getCollisionGeometryResource(collisionRegion.modelURL); + } +} + CollisionRegion CollisionPick::getMathematicalPick() const { - return _mathPick; + if (!parentTransform) { + return _mathPick; + } else { + CollisionRegion transformedMathPick = _mathPick; + transformedMathPick.transform = parentTransform->getTransform().worldTransform(_mathPick.transform); + return transformedMathPick; + } } void CollisionPick::filterIntersections(std::vector& intersections) const { @@ -356,7 +386,7 @@ void CollisionPick::filterIntersections(std::vector& intersec } PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pick) { - if (!isShapeInfoReady()) { + if (!getShapeInfoReady()) { // Cannot compute result return std::make_shared(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } @@ -367,13 +397,13 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi } PickResultPointer CollisionPick::getOverlayIntersection(const CollisionRegion& pick) { - return std::make_shared(pick.toVariantMap(), isShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick, getShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pick) { - if (!isShapeInfoReady()) { + if (!getShapeInfoReady()) { // Cannot compute result - return std::make_shared(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform); @@ -382,5 +412,16 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi } PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) { - return std::make_shared(pick.toVariantMap(), isShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick.toVariantMap(), getShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); +} + +Transform CollisionPick::getResultTransform() const { + PickResultPointer result = getPrevPickResult(); + if (!result) { + return Transform(); + } + + Transform transform; + transform.setTranslation(getMathematicalPick().transform.getTranslation()); + return transform; } \ No newline at end of file diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index 6631238737..12d31111d1 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -11,6 +11,7 @@ #include #include #include +#include #include class CollisionPickResult : public PickResult { @@ -24,12 +25,17 @@ public: CollisionPickResult() {} CollisionPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {} - CollisionPickResult(const CollisionRegion& searchRegion, LoadState loadState, const std::vector& entityIntersections, const std::vector& avatarIntersections) : + CollisionPickResult(const CollisionRegion& searchRegion, + LoadState loadState, + const std::vector& entityIntersections, + const std::vector& avatarIntersections + ) : PickResult(searchRegion.toVariantMap()), loadState(loadState), intersects(entityIntersections.size() || avatarIntersections.size()), entityIntersections(entityIntersections), - avatarIntersections(avatarIntersections) { + avatarIntersections(avatarIntersections) + { } CollisionPickResult(const CollisionPickResult& collisionPickResult) : PickResult(collisionPickResult.pickVariant) { @@ -54,14 +60,7 @@ public: class CollisionPick : public Pick { public: - CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine) : - Pick(filter, maxDistance, enabled), - _mathPick(collisionRegion), - _physicsEngine(physicsEngine) { - if (collisionRegion.shouldComputeShapeInfo()) { - _cachedResource = DependencyManager::get()->getCollisionGeometryResource(collisionRegion.modelURL); - } - } + CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine); CollisionRegion getMathematicalPick() const override; PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { @@ -71,11 +70,12 @@ public: PickResultPointer getOverlayIntersection(const CollisionRegion& pick) override; PickResultPointer getAvatarIntersection(const CollisionRegion& pick) override; PickResultPointer getHUDIntersection(const CollisionRegion& pick) override; - + Transform getResultTransform() const override; protected: // Returns true if pick.shapeInfo is valid. Otherwise, attempts to get the shapeInfo ready for use. - bool isShapeInfoReady(); + bool getShapeInfoReady(); void computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + void computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); void filterIntersections(std::vector& intersections) const; CollisionRegion _mathPick; diff --git a/interface/src/raypick/ParabolaPick.cpp b/interface/src/raypick/ParabolaPick.cpp index b3e3f16345..1b37eee096 100644 --- a/interface/src/raypick/ParabolaPick.cpp +++ b/interface/src/raypick/ParabolaPick.cpp @@ -67,4 +67,16 @@ glm::vec3 ParabolaPick::getAcceleration() const { return scale * (DependencyManager::get()->getMyAvatar()->getWorldOrientation() * _accelerationAxis); } return scale * _accelerationAxis; +} + +Transform ParabolaPick::getResultTransform() const { + PickResultPointer result = getPrevPickResult(); + if (!result) { + return Transform(); + } + + auto parabolaResult = std::static_pointer_cast(result); + Transform transform; + transform.setTranslation(parabolaResult->intersection); + return transform; } \ No newline at end of file diff --git a/interface/src/raypick/ParabolaPick.h b/interface/src/raypick/ParabolaPick.h index 99a42a5380..01454390f9 100644 --- a/interface/src/raypick/ParabolaPick.h +++ b/interface/src/raypick/ParabolaPick.h @@ -83,6 +83,7 @@ public: PickResultPointer getOverlayIntersection(const PickParabola& pick) override; PickResultPointer getAvatarIntersection(const PickParabola& pick) override; PickResultPointer getHUDIntersection(const PickParabola& pick) override; + Transform getResultTransform() const override; protected: float _speed; diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 0ed35e5589..f551c0ec90 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -23,6 +23,13 @@ #include "MouseParabolaPick.h" #include "CollisionPick.h" +#include "SpatialParentFinder.h" +#include "NestableTransformNode.h" +#include "PickTransformNode.h" +#include "MouseTransformNode.h" +#include "avatar/MyAvatarHeadTransformNode.h" +#include "avatar/AvatarManager.h" + #include unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) { @@ -276,8 +283,10 @@ unsigned int PickScriptingInterface::createCollisionPick(const QVariant& propert } CollisionRegion collisionRegion(propMap); + auto collisionPick = std::make_shared(filter, maxDistance, enabled, collisionRegion, qApp->getPhysicsEngine()); + collisionPick->parentTransform = createTransformNode(propMap); - return DependencyManager::get()->addPick(PickQuery::Collision, std::make_shared(filter, maxDistance, enabled, collisionRegion, qApp->getPhysicsEngine())); + return DependencyManager::get()->addPick(PickQuery::Collision, collisionPick); } void PickScriptingInterface::enablePick(unsigned int uid) { @@ -351,3 +360,42 @@ unsigned int PickScriptingInterface::getPerFrameTimeBudget() const { void PickScriptingInterface::setPerFrameTimeBudget(unsigned int numUsecs) { DependencyManager::get()->setPerFrameTimeBudget(numUsecs); } + +std::shared_ptr PickScriptingInterface::createTransformNode(const QVariantMap& propMap) { + if (propMap["parentID"].isValid()) { + QUuid parentUuid = propMap["parentID"].toUuid(); + if (!parentUuid.isNull()) { + // Infer object type from parentID + // For now, assume a QUuuid is a SpatiallyNestable. This should change when picks are converted over to QUuids. + bool success; + std::weak_ptr nestablePointer = DependencyManager::get()->find(parentUuid, success, nullptr); + int parentJointIndex = 0; + if (propMap["parentJointIndex"].isValid()) { + parentJointIndex = propMap["parentJointIndex"].toInt(); + } + if (success && !nestablePointer.expired()) { + return std::make_shared(nestablePointer, parentJointIndex); + } + } + + unsigned int pickID = propMap["parentID"].toUInt(); + if (pickID != 0) { + return std::make_shared(pickID); + } + } + + if (propMap["joint"].isValid()) { + QString joint = propMap["joint"].toString(); + if (joint == "Mouse") { + return std::make_shared(); + } else if (joint == "Avatar") { + return std::make_shared(); + } else if (!joint.isNull()) { + auto myAvatar = DependencyManager::get()->getMyAvatar(); + int jointIndex = myAvatar->getJointIndex(joint); + return std::make_shared(myAvatar, jointIndex); + } + } + + return std::shared_ptr(); +} \ No newline at end of file diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 1cad4abf7c..717436a13b 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -320,6 +320,9 @@ public slots: * @returns {number} */ static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } + +protected: + static std::shared_ptr createTransformNode(const QVariantMap& propMap); }; #endif // hifi_PickScriptingInterface_h diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp index 96b41dcc72..736d3c1760 100644 --- a/interface/src/raypick/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -50,6 +50,18 @@ PickResultPointer RayPick::getHUDIntersection(const PickRay& pick) { return std::make_shared(IntersectionType::HUD, QUuid(), glm::distance(pick.origin, hudRes), hudRes, pick); } +Transform RayPick::getResultTransform() const { + PickResultPointer result = getPrevPickResult(); + if (!result) { + return Transform(); + } + + auto rayResult = std::static_pointer_cast(result); + Transform transform; + transform.setTranslation(rayResult->intersection); + return transform; +} + glm::vec3 RayPick::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration) { // TODO: take into account registration glm::vec3 n = rotation * Vectors::FRONT; diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 9410d39c1a..11f985cec2 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -77,6 +77,7 @@ public: PickResultPointer getOverlayIntersection(const PickRay& pick) override; PickResultPointer getAvatarIntersection(const PickRay& pick) override; PickResultPointer getHUDIntersection(const PickRay& pick) override; + Transform getResultTransform() const override; // These are helper functions for projecting and intersecting rays static glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction); diff --git a/interface/src/raypick/StylusPick.cpp b/interface/src/raypick/StylusPick.cpp index 9021c922a6..69f605e7f9 100644 --- a/interface/src/raypick/StylusPick.cpp +++ b/interface/src/raypick/StylusPick.cpp @@ -225,4 +225,16 @@ PickResultPointer StylusPick::getAvatarIntersection(const StylusTip& pick) { PickResultPointer StylusPick::getHUDIntersection(const StylusTip& pick) { return std::make_shared(pick.toVariantMap()); +} + +Transform StylusPick::getResultTransform() const { + PickResultPointer result = getPrevPickResult(); + if (!result) { + return Transform(); + } + + auto stylusResult = std::static_pointer_cast(result); + Transform transform; + transform.setTranslation(stylusResult->intersection); + return transform; } \ No newline at end of file diff --git a/interface/src/raypick/StylusPick.h b/interface/src/raypick/StylusPick.h index f19e343f8d..ca80e9fbea 100644 --- a/interface/src/raypick/StylusPick.h +++ b/interface/src/raypick/StylusPick.h @@ -66,6 +66,7 @@ public: PickResultPointer getOverlayIntersection(const StylusTip& pick) override; PickResultPointer getAvatarIntersection(const StylusTip& pick) override; PickResultPointer getHUDIntersection(const StylusTip& pick) override; + Transform getResultTransform() const override; bool isLeftHand() const override { return _side == Side::Left; } bool isRightHand() const override { return _side == Side::Right; } diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h index 1a48aac0ef..099a791407 100644 --- a/libraries/pointers/src/Pick.h +++ b/libraries/pointers/src/Pick.h @@ -17,7 +17,7 @@ #include #include -#include +#include enum IntersectionType { NONE = 0, @@ -214,6 +214,10 @@ public: virtual bool isRightHand() const { return false; } virtual bool isMouse() const { return false; } + virtual Transform getResultTransform() const = 0; + + std::shared_ptr parentTransform; + private: PickFilter _filter; const float _maxDistance; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 3c8ee2ed7d..f1c62a8d16 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -258,8 +258,11 @@ public: * @typedef {object} CollisionPick * @property {Shape} shape - The information about the collision region's size and shape. -* @property {Vec3} position - The position of the collision region. -* @property {Quat} orientation - The orientation of the collision region. +* @property {Vec3} position - The position of the collision region, relative to a parent if defined. +* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. +* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. +* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) +* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Head," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. */ class CollisionRegion : public MathPick { public: @@ -305,6 +308,15 @@ public: if (pickVariant["orientation"].isValid()) { transform.setRotation(quatFromVariant(pickVariant["orientation"])); } + if (pickVariant["parentID"].isValid()) { + parentID = pickVariant["parentID"].toString(); + } + if (pickVariant["parentJointIndex"].isValid()) { + parentJointIndex = pickVariant["parentJointIndex"].toInt(); + } + if (pickVariant["joint"].isValid()) { + joint = pickVariant["joint"].toString(); + } } QVariantMap toVariantMap() const override { @@ -320,6 +332,14 @@ public: collisionRegion["position"] = vec3toVariant(transform.getTranslation()); collisionRegion["orientation"] = quatToVariant(transform.getRotation()); + if (!parentID.isNull()) { + collisionRegion["parentID"] = parentID; + } + collisionRegion["parentJointIndex"] = parentJointIndex; + if (!joint.isNull()) { + collisionRegion["joint"] = joint; + } + return collisionRegion; } @@ -354,6 +374,11 @@ public: // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick std::shared_ptr shapeInfo = std::make_shared(); Transform transform; + + // Parenting information + QUuid parentID; + int parentJointIndex = 0; + QString joint; }; namespace std { From cce62f4d928c703a506f53ca26a62ac85d74620f Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 20 Aug 2018 16:59:03 -0700 Subject: [PATCH 05/23] Do not assume picks with doesIntersect()==false have no results to compare. Fixes CollisionPickResult 'loaded' value always evaluating to false when not colliding --- interface/src/raypick/CollisionPick.h | 1 + libraries/pointers/src/Pick.h | 1 + libraries/pointers/src/PickCacheOptimizer.h | 10 +++++----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index 12d31111d1..7ff3670e53 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -53,6 +53,7 @@ public: QVariantMap toVariantMap() const override; bool doesIntersect() const override { return intersects; } + bool needsToCompareResults() const override { return true; } bool checkOrFilterAgainstMaxDistance(float maxDistance) override { return true; } PickResultPointer compareAndProcessNewResult(const PickResultPointer& newRes) override; diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h index 099a791407..9c4de6c46e 100644 --- a/libraries/pointers/src/Pick.h +++ b/libraries/pointers/src/Pick.h @@ -115,6 +115,7 @@ public: } virtual bool doesIntersect() const = 0; + virtual bool needsToCompareResults() const { return doesIntersect(); } // for example: if we want the closest result, compare based on distance // if we want all results, combine them diff --git a/libraries/pointers/src/PickCacheOptimizer.h b/libraries/pointers/src/PickCacheOptimizer.h index 49a039935c..ae515fc8d7 100644 --- a/libraries/pointers/src/PickCacheOptimizer.h +++ b/libraries/pointers/src/PickCacheOptimizer.h @@ -57,8 +57,8 @@ bool PickCacheOptimizer::checkAndCompareCachedResults(T& pick, PickCache& cac } template -void PickCacheOptimizer::cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick) { - if (intersects) { +void PickCacheOptimizer::cacheResult(const bool needToCompareResults, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick) { + if (needToCompareResults) { cache[mathPick][key] = resTemp; res = res->compareAndProcessNewResult(resTemp); } else { @@ -92,7 +92,7 @@ void PickCacheOptimizer::update(std::unordered_mapgetEntityIntersection(mathematicalPick); if (entityRes) { - cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); + cacheResult(entityRes->needsToCompareResults(), entityRes, entityKey, res, mathematicalPick, results, pick); } } } @@ -102,7 +102,7 @@ void PickCacheOptimizer::update(std::unordered_mapgetOverlayIntersection(mathematicalPick); if (overlayRes) { - cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); + cacheResult(overlayRes->needsToCompareResults(), overlayRes, overlayKey, res, mathematicalPick, results, pick); } } } @@ -112,7 +112,7 @@ void PickCacheOptimizer::update(std::unordered_mapgetAvatarIntersection(mathematicalPick); if (avatarRes) { - cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); + cacheResult(avatarRes->needsToCompareResults(), avatarRes, avatarKey, res, mathematicalPick, results, pick); } } } From 51683b0b535f5e987c2a786a325c4e3640d99d41 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 27 Aug 2018 10:16:09 -0700 Subject: [PATCH 06/23] Remove storage of parenting information from CollisionRegion --- libraries/shared/src/RegisteredMetaTypes.h | 27 +--------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index f1c62a8d16..a7f9b72ed2 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -271,10 +271,7 @@ public: CollisionRegion(const CollisionRegion& collisionRegion) : modelURL(collisionRegion.modelURL), shapeInfo(std::make_shared()), - transform(collisionRegion.transform), - parentID(collisionRegion.parentID), - parentJointIndex(collisionRegion.parentJointIndex), - joint(collisionRegion.joint) + transform(collisionRegion.transform) { shapeInfo->setParams(collisionRegion.shapeInfo->getType(), collisionRegion.shapeInfo->getHalfExtents(), collisionRegion.modelURL.toString()); } @@ -308,15 +305,6 @@ public: if (pickVariant["orientation"].isValid()) { transform.setRotation(quatFromVariant(pickVariant["orientation"])); } - if (pickVariant["parentID"].isValid()) { - parentID = pickVariant["parentID"].toString(); - } - if (pickVariant["parentJointIndex"].isValid()) { - parentJointIndex = pickVariant["parentJointIndex"].toInt(); - } - if (pickVariant["joint"].isValid()) { - joint = pickVariant["joint"].toString(); - } } QVariantMap toVariantMap() const override { @@ -332,14 +320,6 @@ public: collisionRegion["position"] = vec3toVariant(transform.getTranslation()); collisionRegion["orientation"] = quatToVariant(transform.getRotation()); - if (!parentID.isNull()) { - collisionRegion["parentID"] = parentID; - } - collisionRegion["parentJointIndex"] = parentJointIndex; - if (!joint.isNull()) { - collisionRegion["joint"] = joint; - } - return collisionRegion; } @@ -374,11 +354,6 @@ public: // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick std::shared_ptr shapeInfo = std::make_shared(); Transform transform; - - // Parenting information - QUuid parentID; - int parentJointIndex = 0; - QString joint; }; namespace std { From 397b03d5d50fec11ed9a84c4e25d63090a317f28 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 27 Aug 2018 14:12:24 -0700 Subject: [PATCH 07/23] Add threshold parameter to collision pick with minimum of 0 --- interface/src/raypick/CollisionPick.cpp | 4 ++-- libraries/physics/src/PhysicsEngine.cpp | 14 ++++++++++---- libraries/physics/src/PhysicsEngine.h | 2 +- libraries/shared/src/RegisteredMetaTypes.h | 19 +++++++++++++++---- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 8c3d28fdfd..407595b86a 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -391,7 +391,7 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi return std::make_shared(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } - auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform); + auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(entityIntersections); return std::make_shared(pick, CollisionPickResult::LOAD_STATE_LOADED, entityIntersections, std::vector()); } @@ -406,7 +406,7 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi return std::make_shared(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } - auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform); + auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(avatarIntersections); return std::make_shared(pick, CollisionPickResult::LOAD_STATE_LOADED, std::vector(), avatarIntersections); } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index d5ce60bef9..58c197d6f4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -898,11 +898,12 @@ void PhysicsEngine::setShowBulletConstraintLimits(bool value) { } struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { - AllContactsCallback(int32_t mask, int32_t group, const ShapeInfo& shapeInfo, const Transform& transform, btCollisionObject* myAvatarCollisionObject) : + AllContactsCallback(int32_t mask, int32_t group, const ShapeInfo& shapeInfo, const Transform& transform, btCollisionObject* myAvatarCollisionObject, float threshold) : btCollisionWorld::ContactResultCallback(), collisionObject(), contacts(), - myAvatarCollisionObject(myAvatarCollisionObject) { + myAvatarCollisionObject(myAvatarCollisionObject), + threshold(threshold) { const btCollisionShape* collisionShape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); collisionObject.setCollisionShape(const_cast(collisionShape)); @@ -924,8 +925,13 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { btCollisionObject collisionObject; std::vector contacts; btCollisionObject* myAvatarCollisionObject; + btScalar threshold; btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0, int partId0, int index0, const btCollisionObjectWrapper* colObj1, int partId1, int index1) override { + if (cp.m_distance1 > -threshold) { + return 0; + } + const btCollisionObject* otherBody; btVector3 penetrationPoint; btVector3 otherPenetrationPoint; @@ -968,14 +974,14 @@ protected: } }; -std::vector PhysicsEngine::contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group) const { +std::vector PhysicsEngine::contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group, float threshold) const { // TODO: Give MyAvatar a motion state so we don't have to do this btCollisionObject* myAvatarCollisionObject = nullptr; if ((mask & USER_COLLISION_GROUP_MY_AVATAR) && _myAvatarController) { myAvatarCollisionObject = _myAvatarController->getCollisionObject(); } - auto contactCallback = AllContactsCallback((int32_t)mask, (int32_t)group, regionShapeInfo, regionTransform, myAvatarCollisionObject); + auto contactCallback = AllContactsCallback((int32_t)mask, (int32_t)group, regionShapeInfo, regionTransform, myAvatarCollisionObject, threshold); _dynamicsWorld->contactTest(&contactCallback.collisionObject, contactCallback); return contactCallback.contacts; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 317f7ef312..09b68d9a8b 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -142,7 +142,7 @@ public: // Function for getting colliding objects in the world of specified type // See PhysicsCollisionGroups.h for mask flags. - std::vector contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC) const; + std::vector contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC, float threshold = 0.0f) const; private: QList removeDynamicsForBody(btRigidBody* body); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index a7f9b72ed2..312e017dc8 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -254,12 +254,13 @@ public: }; /**jsdoc -* A CollisionPick defines a volume for checking collisions in the physics simulation. +* A CollisionRegion defines a volume for checking collisions in the physics simulation. -* @typedef {object} CollisionPick +* @typedef {object} CollisionRegion * @property {Shape} shape - The information about the collision region's size and shape. * @property {Vec3} position - The position of the collision region, relative to a parent if defined. * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Head," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. @@ -269,6 +270,7 @@ public: CollisionRegion() { } CollisionRegion(const CollisionRegion& collisionRegion) : + threshold(collisionRegion.threshold), modelURL(collisionRegion.modelURL), shapeInfo(std::make_shared()), transform(collisionRegion.transform) @@ -299,6 +301,10 @@ public: } } + if (pickVariant["threshold"].isValid()) { + threshold = glm::max(0.0f, pickVariant["threshold"].toFloat()); + } + if (pickVariant["position"].isValid()) { transform.setTranslation(vec3FromVariant(pickVariant["position"])); } @@ -317,6 +323,8 @@ public: collisionRegion["shape"] = shape; + collisionRegion["threshold"] = threshold; + collisionRegion["position"] = vec3toVariant(transform.getTranslation()); collisionRegion["orientation"] = quatToVariant(transform.getRotation()); @@ -324,13 +332,15 @@ public: } operator bool() const override { - return !(glm::any(glm::isnan(transform.getTranslation())) || + return !std::isnan(threshold) && + !(glm::any(glm::isnan(transform.getTranslation())) || glm::any(glm::isnan(transform.getRotation())) || shapeInfo->getType() == SHAPE_TYPE_NONE); } bool operator==(const CollisionRegion& other) const { - return glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) && + return threshold == other.threshold && + glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) && glm::all(glm::equal(transform.getRotation(), other.transform.getRotation())) && glm::all(glm::equal(transform.getScale(), other.transform.getScale())) && shapeInfo->getType() == other.shapeInfo->getType() && @@ -354,6 +364,7 @@ public: // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick std::shared_ptr shapeInfo = std::make_shared(); Transform transform; + float threshold; }; namespace std { From c6e6da2e3f91b0eb0e7db056e1e762c737968a02 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 27 Aug 2018 15:38:36 -0700 Subject: [PATCH 08/23] Make MouseTransformNode actually parent the pick to a mouse rather than a MouseRayPick, and properly include rotation information --- interface/src/raypick/MouseTransformNode.cpp | 42 ++++++-------------- interface/src/raypick/MouseTransformNode.h | 5 --- 2 files changed, 13 insertions(+), 34 deletions(-) diff --git a/interface/src/raypick/MouseTransformNode.cpp b/interface/src/raypick/MouseTransformNode.cpp index 4bc85ae69a..9caa4865a2 100644 --- a/interface/src/raypick/MouseTransformNode.cpp +++ b/interface/src/raypick/MouseTransformNode.cpp @@ -8,36 +8,20 @@ #include "MouseTransformNode.h" -#include "DependencyManager.h" -#include "PickManager.h" -#include "MouseRayPick.h" - -const PickFilter MOUSE_TRANSFORM_NODE_PICK_FILTER( - 1 << PickFilter::PICK_ENTITIES | - 1 << PickFilter::PICK_AVATARS | - 1 << PickFilter::PICK_INCLUDE_NONCOLLIDABLE -); -const float MOUSE_TRANSFORM_NODE_MAX_DISTANCE = 1000.0f; - -MouseTransformNode::MouseTransformNode() { - _parentMouseRayPick = DependencyManager::get()->addPick(PickQuery::Ray, - std::make_shared(MOUSE_TRANSFORM_NODE_PICK_FILTER, MOUSE_TRANSFORM_NODE_MAX_DISTANCE, true)); -} - -MouseTransformNode::~MouseTransformNode() { - if (DependencyManager::isSet()) { - auto pickManager = DependencyManager::get(); - if (pickManager) { - pickManager->removePick(_parentMouseRayPick); - } - } -} +#include "Application.h" +#include "display-plugins/CompositorHelper.h" +#include "RayPick.h" Transform MouseTransformNode::getTransform() { - Transform transform; - std::shared_ptr rayPickResult = DependencyManager::get()->getPrevPickResultTyped(_parentMouseRayPick); - if (rayPickResult) { - transform.setTranslation(rayPickResult->intersection); + QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition(); + if (position.isValid()) { + Transform transform; + QVariantMap posMap = position.toMap(); + PickRay pickRay = qApp->getCamera().computePickRay(posMap["x"].toFloat(), posMap["y"].toFloat()); + transform.setTranslation(pickRay.origin); + transform.setRotation(rotationBetween(Vectors::UP, pickRay.direction)); + return transform; } - return transform; + + return Transform(); } \ No newline at end of file diff --git a/interface/src/raypick/MouseTransformNode.h b/interface/src/raypick/MouseTransformNode.h index 7a05370dd7..4f340339e4 100644 --- a/interface/src/raypick/MouseTransformNode.h +++ b/interface/src/raypick/MouseTransformNode.h @@ -12,12 +12,7 @@ class MouseTransformNode : public TransformNode { public: - MouseTransformNode(); - ~MouseTransformNode(); Transform getTransform() override; - -protected: - unsigned int _parentMouseRayPick = 0; }; #endif // hifi_MouseTransformNode_h \ No newline at end of file From 6f6e70a470e10cb237a8392d23c1e242ccc6fff5 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Tue, 28 Aug 2018 08:45:47 -0700 Subject: [PATCH 09/23] Re-order variable initialization in CollisionRegion copy contructor --- libraries/shared/src/RegisteredMetaTypes.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 312e017dc8..32ecfe8b6d 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -270,10 +270,10 @@ public: CollisionRegion() { } CollisionRegion(const CollisionRegion& collisionRegion) : - threshold(collisionRegion.threshold), modelURL(collisionRegion.modelURL), shapeInfo(std::make_shared()), - transform(collisionRegion.transform) + transform(collisionRegion.transform), + threshold(collisionRegion.threshold) { shapeInfo->setParams(collisionRegion.shapeInfo->getType(), collisionRegion.shapeInfo->getHalfExtents(), collisionRegion.modelURL.toString()); } From 0981f08b22c5f04094428a84d8faeddbdf8b3347 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 14:48:27 -0700 Subject: [PATCH 10/23] Do not propagate avatar scale in AvatarHeadTransformNode --- interface/src/avatar/MyAvatarHeadTransformNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatarHeadTransformNode.cpp b/interface/src/avatar/MyAvatarHeadTransformNode.cpp index 82c2f8b703..9c202ba94a 100644 --- a/interface/src/avatar/MyAvatarHeadTransformNode.cpp +++ b/interface/src/avatar/MyAvatarHeadTransformNode.cpp @@ -19,5 +19,5 @@ Transform MyAvatarHeadTransformNode::getTransform() { glm::quat headOri = myAvatar->getHeadOrientation(); glm::quat ori = headOri * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT); - return Transform(ori, myAvatar->scaleForChildren(), pos); + return Transform(ori, glm::vec3(1.0f), pos); } \ No newline at end of file From 78a438d89a8da8d0a7260c1ac9bb510b27803359 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 14:55:14 -0700 Subject: [PATCH 11/23] Correct CollisionRegion jsdoc for 'joint' parameter --- libraries/shared/src/RegisteredMetaTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 32ecfe8b6d..8fefc37741 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -263,7 +263,7 @@ public: * @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) -* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Head," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. +* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. */ class CollisionRegion : public MathPick { public: From 2d73b7845e95257bd40bf725eb597f28ba90de8f Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 15:00:01 -0700 Subject: [PATCH 12/23] Code style fixes --- interface/src/raypick/CollisionPick.cpp | 3 +-- interface/src/raypick/CollisionPick.h | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 407595b86a..091ceb0794 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -94,8 +94,7 @@ bool CollisionPick::getShapeInfoReady() { } return false; - } - else { + } else { computeShapeInfoDimensionsOnly(_mathPick, *_mathPick.shapeInfo, _cachedResource); return true; } diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index 7ff3670e53..f46f0742f5 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -25,11 +25,7 @@ public: CollisionPickResult() {} CollisionPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {} - CollisionPickResult(const CollisionRegion& searchRegion, - LoadState loadState, - const std::vector& entityIntersections, - const std::vector& avatarIntersections - ) : + CollisionPickResult(const CollisionRegion& searchRegion, LoadState loadState, const std::vector& entityIntersections, const std::vector& avatarIntersections) : PickResult(searchRegion.toVariantMap()), loadState(loadState), intersects(entityIntersections.size() || avatarIntersections.size()), From 686f9fb18a623d6ce93aa988c7ee3f5f27e1c0cb Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 16:12:58 -0700 Subject: [PATCH 13/23] Move load state flag from CollisionPickResult to CollisionRegion and make it a boolean --- interface/src/raypick/CollisionPick.cpp | 48 +++++++++++-------- interface/src/raypick/CollisionPick.h | 17 ++----- .../src/raypick/PickScriptingInterface.h | 3 -- libraries/shared/src/RegisteredMetaTypes.h | 9 +++- 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 091ceb0794..b2137fc80c 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -32,9 +32,6 @@ PickResultPointer CollisionPickResult::compareAndProcessNewResult(const PickResu } intersects = entityIntersections.size() || avatarIntersections.size(); - if (newCollisionResult->loadState == LOAD_STATE_NOT_LOADED || loadState == LOAD_STATE_UNKNOWN) { - loadState = (LoadState)newCollisionResult->loadState; - } return std::make_shared(*this); } @@ -80,24 +77,29 @@ QVariantMap CollisionPickResult::toVariantMap() const { } variantMap["intersectingObjects"] = qIntersectingObjects; - variantMap["loaded"] = (loadState == LOAD_STATE_LOADED); variantMap["collisionRegion"] = pickVariant; return variantMap; } +bool CollisionPick::isLoaded() const { + return !_mathPick.shouldComputeShapeInfo() || (_cachedResource && _cachedResource->isLoaded()); +} + bool CollisionPick::getShapeInfoReady() { if (_mathPick.shouldComputeShapeInfo()) { if (_cachedResource && _cachedResource->isLoaded()) { computeShapeInfo(_mathPick, *_mathPick.shapeInfo, _cachedResource); - return true; + _mathPick.loaded = true; + } else { + _mathPick.loaded = false; } - - return false; } else { computeShapeInfoDimensionsOnly(_mathPick, *_mathPick.shapeInfo, _cachedResource); - return true; + _mathPick.loaded = true; } + + return _mathPick.loaded; } void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { @@ -349,15 +351,19 @@ CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool e if (collisionRegion.shouldComputeShapeInfo()) { _cachedResource = DependencyManager::get()->getCollisionGeometryResource(collisionRegion.modelURL); } + _mathPick.loaded = isLoaded(); } CollisionRegion CollisionPick::getMathematicalPick() const { + CollisionRegion mathPick = _mathPick; + if (!mathPick.loaded) { + mathPick.loaded = isLoaded(); + } if (!parentTransform) { - return _mathPick; + return mathPick; } else { - CollisionRegion transformedMathPick = _mathPick; - transformedMathPick.transform = parentTransform->getTransform().worldTransform(_mathPick.transform); - return transformedMathPick; + mathPick.transform = parentTransform->getTransform().worldTransform(mathPick.transform); + return mathPick; } } @@ -385,33 +391,35 @@ void CollisionPick::filterIntersections(std::vector& intersec } PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pick) { - if (!getShapeInfoReady()) { + if (!pick.loaded) { // Cannot compute result - return std::make_shared(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick.toVariantMap(), std::vector(), std::vector()); } + getShapeInfoReady(); auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(entityIntersections); - return std::make_shared(pick, CollisionPickResult::LOAD_STATE_LOADED, entityIntersections, std::vector()); + return std::make_shared(pick, entityIntersections, std::vector()); } PickResultPointer CollisionPick::getOverlayIntersection(const CollisionRegion& pick) { - return std::make_shared(pick, getShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick, std::vector(), std::vector()); } PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pick) { - if (!getShapeInfoReady()) { + if (!pick.loaded) { // Cannot compute result - return std::make_shared(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick, std::vector(), std::vector()); } + getShapeInfoReady(); auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(avatarIntersections); - return std::make_shared(pick, CollisionPickResult::LOAD_STATE_LOADED, std::vector(), avatarIntersections); + return std::make_shared(pick, std::vector(), avatarIntersections); } PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) { - return std::make_shared(pick.toVariantMap(), getShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); + return std::make_shared(pick.toVariantMap(), std::vector(), std::vector()); } Transform CollisionPick::getResultTransform() const { diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index f46f0742f5..a1636e4b47 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -16,18 +16,11 @@ class CollisionPickResult : public PickResult { public: - enum LoadState { - LOAD_STATE_UNKNOWN, - LOAD_STATE_NOT_LOADED, - LOAD_STATE_LOADED - }; - CollisionPickResult() {} CollisionPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {} - CollisionPickResult(const CollisionRegion& searchRegion, LoadState loadState, const std::vector& entityIntersections, const std::vector& avatarIntersections) : + CollisionPickResult(const CollisionRegion& searchRegion, const std::vector& entityIntersections, const std::vector& avatarIntersections) : PickResult(searchRegion.toVariantMap()), - loadState(loadState), intersects(entityIntersections.size() || avatarIntersections.size()), entityIntersections(entityIntersections), avatarIntersections(avatarIntersections) @@ -38,10 +31,8 @@ public: avatarIntersections = collisionPickResult.avatarIntersections; entityIntersections = collisionPickResult.entityIntersections; intersects = collisionPickResult.intersects; - loadState = collisionPickResult.loadState; } - LoadState loadState { LOAD_STATE_UNKNOWN }; bool intersects { false }; std::vector entityIntersections; std::vector avatarIntersections; @@ -61,7 +52,7 @@ public: CollisionRegion getMathematicalPick() const override; PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { - return std::make_shared(pickVariant, CollisionPickResult::LOAD_STATE_UNKNOWN, std::vector(), std::vector()); + return std::make_shared(pickVariant, std::vector(), std::vector()); } PickResultPointer getEntityIntersection(const CollisionRegion& pick) override; PickResultPointer getOverlayIntersection(const CollisionRegion& pick) override; @@ -69,7 +60,9 @@ public: PickResultPointer getHUDIntersection(const CollisionRegion& pick) override; Transform getResultTransform() const override; protected: - // Returns true if pick.shapeInfo is valid. Otherwise, attempts to get the shapeInfo ready for use. + // Returns true if the resource for _mathPick.shapeInfo is loaded or if a resource is not needed. + bool isLoaded() const; + // Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use. bool getShapeInfoReady(); void computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); void computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 717436a13b..4d99309618 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -152,9 +152,6 @@ public: * @property {CollisionRegion} collisionRegion The CollisionRegion that was used. Valid even if there was no intersection. */ - // TODO: Add this to the CollisionPickResult jsdoc once model collision picks are working - //* @property {boolean} loaded If the CollisionRegion was successfully loaded (may be false if a model was used) - /**jsdoc * Information about the Collision Pick's intersection with an object * diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 8fefc37741..8fb1301484 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -253,6 +253,8 @@ public: } }; +// TODO: Add "loaded" to CollisionRegion jsdoc once model collision picks are supported. + /**jsdoc * A CollisionRegion defines a volume for checking collisions in the physics simulation. @@ -270,6 +272,7 @@ public: CollisionRegion() { } CollisionRegion(const CollisionRegion& collisionRegion) : + loaded(collisionRegion.loaded), modelURL(collisionRegion.modelURL), shapeInfo(std::make_shared()), transform(collisionRegion.transform), @@ -279,6 +282,7 @@ public: } CollisionRegion(const QVariantMap& pickVariant) { + // "loaded" is not deserialized here because there is no way to know if the shape is actually loaded if (pickVariant["shape"].isValid()) { auto shape = pickVariant["shape"].toMap(); if (!shape.empty()) { @@ -322,6 +326,7 @@ public: shape["dimensions"] = vec3toVariant(transform.getScale()); collisionRegion["shape"] = shape; + collisionRegion["loaded"] = loaded; collisionRegion["threshold"] = threshold; @@ -339,7 +344,8 @@ public: } bool operator==(const CollisionRegion& other) const { - return threshold == other.threshold && + return loaded == other.loaded && + threshold == other.threshold && glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) && glm::all(glm::equal(transform.getRotation(), other.transform.getRotation())) && glm::all(glm::equal(transform.getScale(), other.transform.getScale())) && @@ -359,6 +365,7 @@ public: } // We can't load the model here because it would create a circular dependency, so we delegate that responsibility to the owning CollisionPick + bool loaded = false; QUrl modelURL; // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick From 0926968e2bd260ce54a8bb0360632c50dd924921 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 16:17:53 -0700 Subject: [PATCH 14/23] Do not have depth as a parameter in getTransform(..) when called in NestableTransformNode --- libraries/shared/src/NestableTransformNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/NestableTransformNode.cpp b/libraries/shared/src/NestableTransformNode.cpp index 7fb7187aee..17456d69ce 100644 --- a/libraries/shared/src/NestableTransformNode.cpp +++ b/libraries/shared/src/NestableTransformNode.cpp @@ -21,7 +21,7 @@ Transform NestableTransformNode::getTransform() { } bool success; - Transform jointWorldTransform = nestable->getTransform(_jointIndex, success, 30); + Transform jointWorldTransform = nestable->getTransform(_jointIndex, success); if (success) { return jointWorldTransform; From 1fe909f9ad32a01c95dfa15766e8bbcd1cd8acd1 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 16:33:51 -0700 Subject: [PATCH 15/23] Make CollisionPick::getResultTransform() always return a valid transform --- interface/src/raypick/CollisionPick.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index b2137fc80c..b163f23df6 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -423,11 +423,6 @@ PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) } Transform CollisionPick::getResultTransform() const { - PickResultPointer result = getPrevPickResult(); - if (!result) { - return Transform(); - } - Transform transform; transform.setTranslation(getMathematicalPick().transform.getTranslation()); return transform; From a4bb8cb6221747730b27cf6de3ca6e7f41567255 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 30 Aug 2018 09:08:02 -0700 Subject: [PATCH 16/23] Add comment on future of PickTransformNodes --- libraries/pointers/src/PickTransformNode.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/pointers/src/PickTransformNode.h b/libraries/pointers/src/PickTransformNode.h index 7547d3f181..b4c92f3ba7 100644 --- a/libraries/pointers/src/PickTransformNode.h +++ b/libraries/pointers/src/PickTransformNode.h @@ -10,6 +10,7 @@ #include "TransformNode.h" +// TODO: Remove this class when Picks are converted to SpatiallyNestables class PickTransformNode : public TransformNode { public: PickTransformNode(unsigned int uid); From e94d7de99afb4f8914150a9cca3cc524d4fa8503 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 30 Aug 2018 16:05:25 -0700 Subject: [PATCH 17/23] Add JS API hook for getting overlay IDs from a pointer via Pointer.getPointerProperties --- interface/src/raypick/LaserPointer.cpp | 33 ++++++++++++++++++ interface/src/raypick/LaserPointer.h | 2 ++ interface/src/raypick/ParabolaPointer.cpp | 31 +++++++++++++++++ interface/src/raypick/ParabolaPointer.h | 2 ++ .../src/raypick/PointerScriptingInterface.cpp | 34 ++++++++++++------- .../src/raypick/PointerScriptingInterface.h | 8 +++++ interface/src/raypick/StylusPointer.cpp | 4 +++ interface/src/raypick/StylusPointer.h | 2 ++ libraries/pointers/src/Pointer.h | 2 ++ libraries/pointers/src/PointerManager.cpp | 9 +++++ libraries/pointers/src/PointerManager.h | 1 + 11 files changed, 116 insertions(+), 12 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 2382a95105..ee92a0fa6d 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -35,6 +35,39 @@ void LaserPointer::editRenderStatePath(const std::string& state, const QVariant& } } +QVariantMap LaserPointer::toVariantMap() const { + QVariantMap qVariantMap; + + QVariantList qRenderStates; + for (auto iter = _renderStates.cbegin(); iter != _renderStates.cend(); iter++) { + auto renderState = iter->second; + QVariantMap qRenderState; + qRenderState["name"] = iter->first.c_str(); + qRenderState["start"] = renderState->getStartID(); + qRenderState["path"] = std::static_pointer_cast(renderState)->getPathID(); + qRenderState["end"] = renderState->getEndID(); + qRenderStates.append(qRenderState); + } + qVariantMap["renderStates"] = qRenderStates; + + QVariantList qDefaultRenderStates; + for (auto iter = _defaultRenderStates.cbegin(); iter != _defaultRenderStates.cend(); iter++) { + float distance = iter->second.first; + auto defaultRenderState = iter->second.second; + QVariantMap qDefaultRenderState; + + qDefaultRenderState["name"] = iter->first.c_str(); + qDefaultRenderState["distance"] = distance; + qDefaultRenderState["start"] = defaultRenderState->getStartID(); + qDefaultRenderState["path"] = std::static_pointer_cast(defaultRenderState)->getPathID(); + qDefaultRenderState["end"] = defaultRenderState->getEndID(); + qDefaultRenderStates.append(qDefaultRenderState); + } + qVariantMap["defaultRenderStates"] = qDefaultRenderStates; + + return qVariantMap; +} + glm::vec3 LaserPointer::getPickOrigin(const PickResultPointer& pickResult) const { auto rayPickResult = std::static_pointer_cast(pickResult); return (rayPickResult ? vec3FromVariant(rayPickResult->pickVariant["origin"]) : glm::vec3(0.0f)); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 95a5bccc6c..c0ac3259d9 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -42,6 +42,8 @@ public: LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers, bool faceAvatar, bool followNormal, float followNormalStrength, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool scaleWithAvatar, bool enabled); + QVariantMap toVariantMap() const override; + static std::shared_ptr buildRenderState(const QVariantMap& propMap); protected: diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp index 097c98340c..b8c6224f08 100644 --- a/interface/src/raypick/ParabolaPointer.cpp +++ b/interface/src/raypick/ParabolaPointer.cpp @@ -60,6 +60,37 @@ void ParabolaPointer::editRenderStatePath(const std::string& state, const QVaria } } +QVariantMap ParabolaPointer::toVariantMap() const { + QVariantMap qVariantMap; + + QVariantList qRenderStates; + for (auto iter = _renderStates.cbegin(); iter != _renderStates.cend(); iter++) { + auto renderState = iter->second; + QVariantMap qRenderState; + qRenderState["name"] = iter->first.c_str(); + qRenderState["start"] = renderState->getStartID(); + qRenderState["end"] = renderState->getEndID(); + qRenderStates.append(qRenderState); + } + qVariantMap["renderStates"] = qRenderStates; + + QVariantList qDefaultRenderStates; + for (auto iter = _defaultRenderStates.cbegin(); iter != _defaultRenderStates.cend(); iter++) { + float distance = iter->second.first; + auto defaultRenderState = iter->second.second; + QVariantMap qDefaultRenderState; + + qDefaultRenderState["name"] = iter->first.c_str(); + qDefaultRenderState["distance"] = distance; + qDefaultRenderState["start"] = defaultRenderState->getStartID(); + qDefaultRenderState["end"] = defaultRenderState->getEndID(); + qDefaultRenderStates.append(qDefaultRenderState); + } + qVariantMap["defaultRenderStates"] = qDefaultRenderStates; + + return qVariantMap; +} + glm::vec3 ParabolaPointer::getPickOrigin(const PickResultPointer& pickResult) const { auto parabolaPickResult = std::static_pointer_cast(pickResult); return (parabolaPickResult ? vec3FromVariant(parabolaPickResult->pickVariant["origin"]) : glm::vec3(0.0f)); diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h index 93f9a7b055..526abe3b0d 100644 --- a/interface/src/raypick/ParabolaPointer.h +++ b/interface/src/raypick/ParabolaPointer.h @@ -97,6 +97,8 @@ public: ParabolaPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers, bool faceAvatar, bool followNormal, float followNormalStrength, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool scaleWithAvatar, bool enabled); + QVariantMap toVariantMap() const override; + static std::shared_ptr buildRenderState(const QVariantMap& propMap); protected: diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index a9b9b6e9ea..cd3ffdac82 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -76,16 +76,19 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) * @property {number} distance The distance at which to render the end of this Ray Pointer, if one is defined. */ /**jsdoc - * A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something. + * A set of properties which define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something. * * @typedef {object} Pointers.RayPointerRenderState * @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} - * @property {Overlays.OverlayProperties} [start] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). - * An overlay to represent the beginning of the Ray Pointer, if desired. - * @property {Overlays.OverlayProperties} [path] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field), which must be "line3d". - * An overlay to represent the path of the Ray Pointer, if desired. - * @property {Overlays.OverlayProperties} [end] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). - * An overlay to represent the end of the Ray Pointer, if desired. + * @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Ray Pointer, + * using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). + * When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. + * @property {Overlays.OverlayProperties|QUuid} [path] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the path of the Ray Pointer, + * using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field), which must be "line3d". + * When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. + * @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the end of the Ray Pointer, + * using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). + * When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. */ /**jsdoc * A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick. @@ -225,11 +228,14 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope * * @typedef {object} Pointers.ParabolaPointerRenderState * @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} -* @property {Overlays.OverlayProperties} [start] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). -* An overlay to represent the beginning of the Parabola Pointer, if desired. -* @property {Pointers.ParabolaProperties} [path] The rendering properties of the parabolic path defined by the Parabola Pointer. -* @property {Overlays.OverlayProperties} [end] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). -* An overlay to represent the end of the Parabola Pointer, if desired. +* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Parabola Pointer, +* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). +* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. +* @property {Pointers.ParabolaProperties} [path] When using {@link Pointers.createPointer}, the optionally defined rendering properties of the parabolic path defined by the Parabola Pointer. +* Not defined in {@link Pointers.getPointerProperties}. +* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the end of the Parabola Pointer, +* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). +* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. */ /**jsdoc * A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick. @@ -375,4 +381,8 @@ QVariantMap PointerScriptingInterface::getPrevPickResult(unsigned int uid) const result = pickResult->toVariantMap(); } return result; +} + +QVariantMap PointerScriptingInterface::getPointerProperties(unsigned int uid) const { + return DependencyManager::get()->getPointerProperties(uid); } \ No newline at end of file diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 9fe05182c7..94f1d62552 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -203,6 +203,14 @@ public: */ Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get()->isMouse(uid); } + /**jsdoc + * Returns information about an existing Pointer + * @function Pointers.getPointerState + * @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}. + * @returns {Pointers.LaserPointerProperties|Pointers.StylusPointerProperties|Pointers.ParabolaPointerProperties} The information about the Pointer. + * Currently only includes renderStates and defaultRenderStates with associated overlay IDs. + */ + Q_INVOKABLE QVariantMap getPointerProperties(unsigned int uid) const; }; #endif // hifi_PointerScriptingInterface_h diff --git a/interface/src/raypick/StylusPointer.cpp b/interface/src/raypick/StylusPointer.cpp index 8c0fb59106..d963b0c670 100644 --- a/interface/src/raypick/StylusPointer.cpp +++ b/interface/src/raypick/StylusPointer.cpp @@ -203,6 +203,10 @@ void StylusPointer::setRenderState(const std::string& state) { } } +QVariantMap StylusPointer::toVariantMap() const { + return QVariantMap(); +} + glm::vec3 StylusPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) { switch (pickedObject.type) { case ENTITY: diff --git a/interface/src/raypick/StylusPointer.h b/interface/src/raypick/StylusPointer.h index 950b03b7c9..1fe8b047e5 100644 --- a/interface/src/raypick/StylusPointer.h +++ b/interface/src/raypick/StylusPointer.h @@ -33,6 +33,8 @@ public: void setRenderState(const std::string& state) override; void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override {} + QVariantMap toVariantMap() const override; + static OverlayID buildStylusOverlay(const QVariantMap& properties); protected: diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h index 0c842dbd88..4264a60079 100644 --- a/libraries/pointers/src/Pointer.h +++ b/libraries/pointers/src/Pointer.h @@ -50,6 +50,8 @@ public: virtual void setRenderState(const std::string& state) = 0; virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) = 0; + virtual QVariantMap toVariantMap() const = 0; + virtual void setPrecisionPicking(bool precisionPicking); virtual void setIgnoreItems(const QVector& ignoreItems) const; virtual void setIncludeItems(const QVector& includeItems) const; diff --git a/libraries/pointers/src/PointerManager.cpp b/libraries/pointers/src/PointerManager.cpp index be890da392..922f0bb5bc 100644 --- a/libraries/pointers/src/PointerManager.cpp +++ b/libraries/pointers/src/PointerManager.cpp @@ -77,6 +77,15 @@ PickResultPointer PointerManager::getPrevPickResult(unsigned int uid) const { return result; } +QVariantMap PointerManager::getPointerProperties(unsigned int uid) const { + auto pointer = find(uid); + if (pointer) { + return pointer->toVariantMap(); + } else { + return QVariantMap(); + } +} + void PointerManager::update() { auto cachedPointers = resultWithReadLock>>([&] { return _pointers; diff --git a/libraries/pointers/src/PointerManager.h b/libraries/pointers/src/PointerManager.h index b98558622f..2d0b2a107e 100644 --- a/libraries/pointers/src/PointerManager.h +++ b/libraries/pointers/src/PointerManager.h @@ -30,6 +30,7 @@ public: void setRenderState(unsigned int uid, const std::string& renderState) const; void editRenderState(unsigned int uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; PickResultPointer getPrevPickResult(unsigned int uid) const; + QVariantMap getPointerProperties(unsigned int uid) const; void setPrecisionPicking(unsigned int uid, bool precisionPicking) const; void setIgnoreItems(unsigned int uid, const QVector& ignoreEntities) const; From 9bf088d32b9c803c4974061ced8170b7ed999185 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 31 Aug 2018 10:28:45 -0700 Subject: [PATCH 18/23] Just assign mathPick.loaded in CollisionPick::getMathematicalPick --- interface/src/raypick/CollisionPick.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index b163f23df6..654378cc9b 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -356,9 +356,7 @@ CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool e CollisionRegion CollisionPick::getMathematicalPick() const { CollisionRegion mathPick = _mathPick; - if (!mathPick.loaded) { - mathPick.loaded = isLoaded(); - } + mathPick.loaded = isLoaded(); if (!parentTransform) { return mathPick; } else { From 4d85cb17f36b4f73582419ee944492725e1f5db3 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 31 Aug 2018 10:46:17 -0700 Subject: [PATCH 19/23] Include full transform in CollisionPick::getResultTransform --- interface/src/raypick/CollisionPick.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 654378cc9b..7d0276875b 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -421,7 +421,5 @@ PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) } Transform CollisionPick::getResultTransform() const { - Transform transform; - transform.setTranslation(getMathematicalPick().transform.getTranslation()); - return transform; + return Transform(getMathematicalPick().transform); } \ No newline at end of file From f71fc833099aaa678f41779adc9fd1a2bf439c97 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 31 Aug 2018 10:48:48 -0700 Subject: [PATCH 20/23] Remove PickResult::needsToCompareResults --- interface/src/raypick/CollisionPick.h | 1 - libraries/pointers/src/Pick.h | 1 - libraries/pointers/src/PickCacheOptimizer.h | 6 +++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index a1636e4b47..ce8b3bd199 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -40,7 +40,6 @@ public: QVariantMap toVariantMap() const override; bool doesIntersect() const override { return intersects; } - bool needsToCompareResults() const override { return true; } bool checkOrFilterAgainstMaxDistance(float maxDistance) override { return true; } PickResultPointer compareAndProcessNewResult(const PickResultPointer& newRes) override; diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h index 9c4de6c46e..099a791407 100644 --- a/libraries/pointers/src/Pick.h +++ b/libraries/pointers/src/Pick.h @@ -115,7 +115,6 @@ public: } virtual bool doesIntersect() const = 0; - virtual bool needsToCompareResults() const { return doesIntersect(); } // for example: if we want the closest result, compare based on distance // if we want all results, combine them diff --git a/libraries/pointers/src/PickCacheOptimizer.h b/libraries/pointers/src/PickCacheOptimizer.h index ae515fc8d7..448d67b5a9 100644 --- a/libraries/pointers/src/PickCacheOptimizer.h +++ b/libraries/pointers/src/PickCacheOptimizer.h @@ -92,7 +92,7 @@ void PickCacheOptimizer::update(std::unordered_mapgetEntityIntersection(mathematicalPick); if (entityRes) { - cacheResult(entityRes->needsToCompareResults(), entityRes, entityKey, res, mathematicalPick, results, pick); + cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); } } } @@ -102,7 +102,7 @@ void PickCacheOptimizer::update(std::unordered_mapgetOverlayIntersection(mathematicalPick); if (overlayRes) { - cacheResult(overlayRes->needsToCompareResults(), overlayRes, overlayKey, res, mathematicalPick, results, pick); + cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); } } } @@ -112,7 +112,7 @@ void PickCacheOptimizer::update(std::unordered_mapgetAvatarIntersection(mathematicalPick); if (avatarRes) { - cacheResult(avatarRes->needsToCompareResults(), avatarRes, avatarKey, res, mathematicalPick, results, pick); + cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); } } } From 2e290ea798254481fe7dd91af5916686a4543f29 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 31 Aug 2018 10:52:00 -0700 Subject: [PATCH 21/23] Only create a NestableTransformNode if the spatially nestable exists --- interface/src/raypick/PickScriptingInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index f551c0ec90..6dedf3fca1 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -373,7 +373,8 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const if (propMap["parentJointIndex"].isValid()) { parentJointIndex = propMap["parentJointIndex"].toInt(); } - if (success && !nestablePointer.expired()) { + auto sharedNestablePointer = nestablePointer.lock(); + if (success && sharedNestablePointer) { return std::make_shared(nestablePointer, parentJointIndex); } } From b5862aca2aa8c4d397f8f962468cccf4d205576c Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 31 Aug 2018 10:53:20 -0700 Subject: [PATCH 22/23] Use bracket initialization for CollisionRegion.loaded --- libraries/shared/src/RegisteredMetaTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 8fb1301484..02f5fa570c 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -365,7 +365,7 @@ public: } // We can't load the model here because it would create a circular dependency, so we delegate that responsibility to the owning CollisionPick - bool loaded = false; + bool loaded { false }; QUrl modelURL; // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick From 62344c106dadb5fe54687f7c9b9d1c8b4ab34e46 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 31 Aug 2018 11:19:53 -0700 Subject: [PATCH 23/23] Make render states a map when returned from PointerScriptingInterface::getPointerProperties --- interface/src/raypick/LaserPointer.cpp | 10 ++++------ interface/src/raypick/ParabolaPointer.cpp | 10 ++++------ .../src/raypick/PointerScriptingInterface.cpp | 20 +++++++++++++------ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index ee92a0fa6d..afbb278dc7 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -38,30 +38,28 @@ void LaserPointer::editRenderStatePath(const std::string& state, const QVariant& QVariantMap LaserPointer::toVariantMap() const { QVariantMap qVariantMap; - QVariantList qRenderStates; + QVariantMap qRenderStates; for (auto iter = _renderStates.cbegin(); iter != _renderStates.cend(); iter++) { auto renderState = iter->second; QVariantMap qRenderState; - qRenderState["name"] = iter->first.c_str(); qRenderState["start"] = renderState->getStartID(); qRenderState["path"] = std::static_pointer_cast(renderState)->getPathID(); qRenderState["end"] = renderState->getEndID(); - qRenderStates.append(qRenderState); + qRenderStates[iter->first.c_str()] = qRenderState; } qVariantMap["renderStates"] = qRenderStates; - QVariantList qDefaultRenderStates; + QVariantMap qDefaultRenderStates; for (auto iter = _defaultRenderStates.cbegin(); iter != _defaultRenderStates.cend(); iter++) { float distance = iter->second.first; auto defaultRenderState = iter->second.second; QVariantMap qDefaultRenderState; - qDefaultRenderState["name"] = iter->first.c_str(); qDefaultRenderState["distance"] = distance; qDefaultRenderState["start"] = defaultRenderState->getStartID(); qDefaultRenderState["path"] = std::static_pointer_cast(defaultRenderState)->getPathID(); qDefaultRenderState["end"] = defaultRenderState->getEndID(); - qDefaultRenderStates.append(qDefaultRenderState); + qDefaultRenderStates[iter->first.c_str()] = qDefaultRenderState; } qVariantMap["defaultRenderStates"] = qDefaultRenderStates; diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp index b8c6224f08..fc3aecdb51 100644 --- a/interface/src/raypick/ParabolaPointer.cpp +++ b/interface/src/raypick/ParabolaPointer.cpp @@ -63,28 +63,26 @@ void ParabolaPointer::editRenderStatePath(const std::string& state, const QVaria QVariantMap ParabolaPointer::toVariantMap() const { QVariantMap qVariantMap; - QVariantList qRenderStates; + QVariantMap qRenderStates; for (auto iter = _renderStates.cbegin(); iter != _renderStates.cend(); iter++) { auto renderState = iter->second; QVariantMap qRenderState; - qRenderState["name"] = iter->first.c_str(); qRenderState["start"] = renderState->getStartID(); qRenderState["end"] = renderState->getEndID(); - qRenderStates.append(qRenderState); + qRenderStates[iter->first.c_str()] = qRenderState; } qVariantMap["renderStates"] = qRenderStates; - QVariantList qDefaultRenderStates; + QVariantMap qDefaultRenderStates; for (auto iter = _defaultRenderStates.cbegin(); iter != _defaultRenderStates.cend(); iter++) { float distance = iter->second.first; auto defaultRenderState = iter->second.second; QVariantMap qDefaultRenderState; - qDefaultRenderState["name"] = iter->first.c_str(); qDefaultRenderState["distance"] = distance; qDefaultRenderState["start"] = defaultRenderState->getStartID(); qDefaultRenderState["end"] = defaultRenderState->getEndID(); - qDefaultRenderStates.append(qDefaultRenderState); + qDefaultRenderStates[iter->first.c_str()] = qDefaultRenderState; } qVariantMap["defaultRenderStates"] = qDefaultRenderStates; diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index cd3ffdac82..7209e402a1 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -79,7 +79,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) * A set of properties which define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something. * * @typedef {object} Pointers.RayPointerRenderState - * @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} + * @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} * @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Ray Pointer, * using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). * When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. @@ -102,8 +102,12 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) * @property {number} [followNormalStrength=0.0] The strength of the interpolation between the real normal and the visual normal if followNormal is true. 0-1. If 0 or 1, * the normal will follow exactly. * @property {boolean} [enabled=false] - * @property {Pointers.RayPointerRenderState[]} [renderStates] A list of different visual states to switch between. - * @property {Pointers.DefaultRayPointerRenderState[]} [defaultRenderStates] A list of different visual states to use if there is no intersection. + * @property {Pointers.RayPointerRenderState[]|Object.} [renderStates] A collection of different visual states to switch between. + * When using {@link Pointers.createPointer}, a list of RayPointerRenderStates. + * When returned from {@link Pointers.getPointerProperties}, a map between render state names and RayPointRenderStates. + * @property {Pointers.DefaultRayPointerRenderState[]|Object.} [defaultRenderStates] A collection of different visual states to use if there is no intersection. + * When using {@link Pointers.createPointer}, a list of DefaultRayPointerRenderStates. + * When returned from {@link Pointers.getPointerProperties}, a map between render state names and DefaultRayPointRenderStates. * @property {boolean} [hover=false] If this Pointer should generate hover events. * @property {Pointers.Trigger[]} [triggers] A list of different triggers mechanisms that control this Pointer's click event generation. */ @@ -227,7 +231,7 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope * A set of properties used to define the visual aspect of a Parabola Pointer in the case that the Pointer is intersecting something. * * @typedef {object} Pointers.ParabolaPointerRenderState -* @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} +* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} * @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Parabola Pointer, * using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). * When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise. @@ -249,8 +253,12 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope * @property {number} [followNormalStrength=0.0] The strength of the interpolation between the real normal and the visual normal if followNormal is true. 0-1. If 0 or 1, * the normal will follow exactly. * @property {boolean} [enabled=false] -* @property {Pointers.ParabolaPointerRenderState[]} [renderStates] A list of different visual states to switch between. -* @property {Pointers.DefaultParabolaPointerRenderState[]} [defaultRenderStates] A list of different visual states to use if there is no intersection. +* @property {Pointers.ParabolaPointerRenderState[]|Object.} [renderStates] A collection of different visual states to switch between. +* When using {@link Pointers.createPointer}, a list of ParabolaPointerRenderStates. +* When returned from {@link Pointers.getPointerProperties}, a map between render state names and ParabolaPointerRenderStates. +* @property {Pointers.DefaultParabolaPointerRenderState[]|Object.} [defaultRenderStates] A collection of different visual states to use if there is no intersection. +* When using {@link Pointers.createPointer}, a list of DefaultParabolaPointerRenderStates. +* When returned from {@link Pointers.getPointerProperties}, a map between render state names and DefaultParabolaPointerRenderStates. * @property {boolean} [hover=false] If this Pointer should generate hover events. * @property {Pointers.Trigger[]} [triggers] A list of different triggers mechanisms that control this Pointer's click event generation. */