From 3167d3c0c726f791fff2d3c3041618e3032cd57a Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 23 Aug 2018 14:05:44 -0700 Subject: [PATCH 01/61] 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/61] 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/61] 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/61] 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/61] 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 62814deb328201ba6fe3a122514c9fbc5d61a730 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 27 Aug 2018 08:34:01 -0700 Subject: [PATCH 06/61] Added read of map_d from MTL files --- libraries/fbx/src/OBJReader.cpp | 31 +++++++++++++++++++++---------- libraries/fbx/src/OBJReader.h | 2 ++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index caac08f777..501fb72130 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -263,15 +263,19 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { default: materials[matName] = currentMaterial; #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel << - " shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << - " diffuse color:" << currentMaterial.diffuseColor << " specular color:" << - currentMaterial.specularColor << " emissive color:" << currentMaterial.emissiveColor << - " diffuse texture:" << currentMaterial.diffuseTextureFilename << " specular texture:" << - currentMaterial.specularTextureFilename << " emissive texture:" << - currentMaterial.emissiveTextureFilename << " bump texture:" << - currentMaterial.bumpTextureFilename; - #endif + qCDebug(modelformat) << + "OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel << + " shininess:" << currentMaterial.shininess << + " opacity:" << currentMaterial.opacity << + " diffuse color:" << currentMaterial.diffuseColor << + " specular color:" << currentMaterial.specularColor << + " emissive color:" << currentMaterial.emissiveColor << + " diffuse texture:" << currentMaterial.diffuseTextureFilename << + " specular texture:" << currentMaterial.specularTextureFilename << + " emissive texture:" << currentMaterial.emissiveTextureFilename << + " bump texture:" << currentMaterial.bumpTextureFilename; + " opacity texture:" << currentMaterial.opacityTextureFilename; +#endif return; } QByteArray token = tokenizer.getDatum(); @@ -289,6 +293,8 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.emissiveTextureFilename = ""; currentMaterial.specularTextureFilename = ""; currentMaterial.bumpTextureFilename = ""; + currentMaterial.opacityTextureFilename = ""; + } else if (token == "Ns") { currentMaterial.shininess = tokenizer.getFloat(); } else if (token == "Ni") { @@ -321,7 +327,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); - } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump") || (token == "bump")) { + } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump") || (token == "bump") || (token == "map_d")) { const QByteArray textureLine = tokenizer.getLineAsDatum(); QByteArray filename; OBJMaterialTextureOptions textureOptions; @@ -341,6 +347,8 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if ((token == "map_bump") || (token == "bump")) { currentMaterial.bumpTextureFilename = filename; currentMaterial.bumpTextureOptions = textureOptions; + } else if (token == "map_d") { + currentMaterial.opacityTextureFilename = filename; } } } @@ -900,6 +908,9 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m fbxMaterial.normalTexture.isBumpmap = true; fbxMaterial.bumpMultiplier = objMaterial.bumpTextureOptions.bumpMultiplier; } + if (!objMaterial.opacityTextureFilename.isEmpty()) { + fbxMaterial.opacityTexture.filename = objMaterial.opacityTextureFilename; + } modelMaterial->setEmissive(fbxMaterial.emissiveColor); modelMaterial->setAlbedo(fbxMaterial.diffuseColor); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 13ddc6e21c..e432a3ea51 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -66,6 +66,8 @@ public: QByteArray specularTextureFilename; QByteArray emissiveTextureFilename; QByteArray bumpTextureFilename; + QByteArray opacityTextureFilename; + OBJMaterialTextureOptions bumpTextureOptions; int illuminationModel; bool used { false }; From 51683b0b535f5e987c2a786a325c4e3640d99d41 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 27 Aug 2018 10:16:09 -0700 Subject: [PATCH 07/61] 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 08/61] 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 09/61] 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 10/61] 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 bf348f43aa55d790423f6e5a828e0372e9843f90 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 29 Aug 2018 09:55:54 -0700 Subject: [PATCH 11/61] Prepare for runtime CPU dispatch of all SIMD functions --- libraries/audio/src/AudioHRTF.cpp | 54 ++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 23adcde0c5..aef4ef3326 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -276,23 +276,8 @@ static void FIR_1x4_SSE(float* src, float* dst0, float* dst1, float* dst2, float } } -// -// Runtime CPU dispatch -// - -#include "CPUDetect.h" - -void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); -void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); - -static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { - - static auto f = cpuSupportsAVX512() ? FIR_1x4_AVX512 : (cpuSupportsAVX2() ? FIR_1x4_AVX2 : FIR_1x4_SSE); - (*f)(src, dst0, dst1, dst2, dst3, coef, numFrames); // dispatch -} - // 4 channel planar to interleaved -static void interleave_4x4(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames) { +static void interleave_4x4_SSE(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames) { assert(numFrames % 4 == 0); @@ -323,7 +308,7 @@ static void interleave_4x4(float* src0, float* src1, float* src2, float* src3, f // process 2 cascaded biquads on 4 channels (interleaved) // biquads computed in parallel, by adding one sample of delay -static void biquad2_4x4(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { +static void biquad2_4x4_SSE(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { // enable flush-to-zero mode to prevent denormals unsigned int ftz = _MM_GET_FLUSH_ZERO_MODE(); @@ -388,7 +373,7 @@ static void biquad2_4x4(float* src, float* dst, float coef[5][8], float state[3] } // crossfade 4 inputs into 2 outputs with accumulation (interleaved) -static void crossfade_4x2(float* src, float* dst, const float* win, int numFrames) { +static void crossfade_4x2_SSE(float* src, float* dst, const float* win, int numFrames) { assert(numFrames % 4 == 0); @@ -435,7 +420,7 @@ static void crossfade_4x2(float* src, float* dst, const float* win, int numFrame } // linear interpolation with gain -static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) { +static void interpolate_SSE(float* dst, const float* src0, const float* src1, float frac, float gain) { __m128 f0 = _mm_set1_ps(gain * (1.0f - frac)); __m128 f1 = _mm_set1_ps(gain * frac); @@ -453,6 +438,37 @@ static void interpolate(float* dst, const float* src0, const float* src1, float } } +// +// Runtime CPU dispatch +// + +#include "CPUDetect.h" + +void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); +void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); + +static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { + + static auto f = cpuSupportsAVX512() ? FIR_1x4_AVX512 : (cpuSupportsAVX2() ? FIR_1x4_AVX2 : FIR_1x4_SSE); + (*f)(src, dst0, dst1, dst2, dst3, coef, numFrames); // dispatch +} + +static void interleave_4x4(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames) { + interleave_4x4_SSE(src0, src1, src2, src3, dst, numFrames); +} + +static void biquad2_4x4(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { + biquad2_4x4_SSE(src, dst, coef, state, numFrames); +} + +static void crossfade_4x2(float* src, float* dst, const float* win, int numFrames) { + crossfade_4x2_SSE(src, dst, win, numFrames); +} + +static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) { + interpolate_SSE(dst, src0, src1, frac, gain); +} + #else // portable reference code // 1 channel input, 4 channel output From 6f151ad2837cb252dd8ea16c5baa3e415ca23363 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 29 Aug 2018 10:03:40 -0700 Subject: [PATCH 12/61] Consistent parameter order for SIMD functions --- libraries/audio/src/AudioHRTF.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index aef4ef3326..20d782a414 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -420,7 +420,7 @@ static void crossfade_4x2_SSE(float* src, float* dst, const float* win, int numF } // linear interpolation with gain -static void interpolate_SSE(float* dst, const float* src0, const float* src1, float frac, float gain) { +static void interpolate_SSE(const float* src0, const float* src1, float* dst, float frac, float gain) { __m128 f0 = _mm_set1_ps(gain * (1.0f - frac)); __m128 f1 = _mm_set1_ps(gain * frac); @@ -465,8 +465,8 @@ static void crossfade_4x2(float* src, float* dst, const float* win, int numFrame crossfade_4x2_SSE(src, dst, win, numFrames); } -static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) { - interpolate_SSE(dst, src0, src1, frac, gain); +static void interpolate(const float* src0, const float* src1, float* dst, float frac, float gain) { + interpolate_SSE(src0, src1, dst, frac, gain); } #else // portable reference code @@ -731,7 +731,7 @@ static void crossfade_4x2(float* src, float* dst, const float* win, int numFrame } // linear interpolation with gain -static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) { +static void interpolate(const float* src0, const float* src1, float* dst, float frac, float gain) { float f0 = gain * (1.0f - frac); float f1 = gain * frac; @@ -983,8 +983,8 @@ static void setFilters(float firCoef[4][HRTF_TAPS], float bqCoef[5][8], int dela azimuthToIndex(azimuth, az0, az1, frac); // interpolate FIR - interpolate(firCoef[channel+0], ir_table_table[index][azL0][0], ir_table_table[index][azL1][0], fracL, gain * gainL); - interpolate(firCoef[channel+1], ir_table_table[index][azR0][1], ir_table_table[index][azR1][1], fracR, gain * gainR); + interpolate(ir_table_table[index][azL0][0], ir_table_table[index][azL1][0], firCoef[channel+0], fracL, gain * gainL); + interpolate(ir_table_table[index][azR0][1], ir_table_table[index][azR1][1], firCoef[channel+1], fracR, gain * gainR); // interpolate ITD float itd = (1.0f - frac) * itd_table_table[index][az0] + frac * itd_table_table[index][az1]; From 3e17556cc1c14c7263d8f27cf440476c7be22451 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 29 Aug 2018 10:47:02 -0700 Subject: [PATCH 13/61] Prefer static_assert() over assert() --- libraries/audio/src/AudioHRTF.cpp | 6 +++--- libraries/audio/src/avx2/AudioHRTF_avx2.cpp | 2 +- libraries/audio/src/avx512/AudioHRTF_avx512.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 20d782a414..7895a70595 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -240,7 +240,7 @@ static void FIR_1x4_SSE(float* src, float* dst0, float* dst1, float* dst2, float float* ps = &src[i - HRTF_TAPS + 1]; // process forwards - assert(HRTF_TAPS % 4 == 0); + static_assert(HRTF_TAPS % 4 == 0, "HRTF_TAPS must be a multiple of 4"); for (int k = 0; k < HRTF_TAPS; k += 4) { @@ -425,7 +425,7 @@ static void interpolate_SSE(const float* src0, const float* src1, float* dst, fl __m128 f0 = _mm_set1_ps(gain * (1.0f - frac)); __m128 f1 = _mm_set1_ps(gain * frac); - assert(HRTF_TAPS % 4 == 0); + static_assert(HRTF_TAPS % 4 == 0, "HRTF_TAPS must be a multiple of 4"); for (int k = 0; k < HRTF_TAPS; k += 4) { @@ -505,7 +505,7 @@ static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* ds float* ps = &src[i - HRTF_TAPS + 1]; // process forwards - assert(HRTF_TAPS % 4 == 0); + static_assert(HRTF_TAPS % 4 == 0, "HRTF_TAPS must be a multiple of 4"); for (int k = 0; k < HRTF_TAPS; k += 4) { diff --git a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp index e89128b173..501f010236 100644 --- a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp +++ b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp @@ -44,7 +44,7 @@ void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3 float* ps = &src[i - HRTF_TAPS + 1]; // process forwards - assert(HRTF_TAPS % 4 == 0); + static_assert(HRTF_TAPS % 4 == 0, "HRTF_TAPS must be a multiple of 4"); for (int k = 0; k < HRTF_TAPS; k += 4) { diff --git a/libraries/audio/src/avx512/AudioHRTF_avx512.cpp b/libraries/audio/src/avx512/AudioHRTF_avx512.cpp index a8bb62be35..fcec81fa4c 100644 --- a/libraries/audio/src/avx512/AudioHRTF_avx512.cpp +++ b/libraries/audio/src/avx512/AudioHRTF_avx512.cpp @@ -44,7 +44,7 @@ void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* ds float* ps = &src[i - HRTF_TAPS + 1]; // process forwards - assert(HRTF_TAPS % 4 == 0); + static_assert(HRTF_TAPS % 4 == 0, "HRTF_TAPS must be a multiple of 4"); for (int k = 0; k < HRTF_TAPS; k += 4) { From f9d14e135149d977640f09308ec791cf6fb52b28 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Aug 2018 11:17:11 -0700 Subject: [PATCH 14/61] filter time-cost drivers for region regulation --- interface/src/Application.cpp | 14 +++-- libraries/shared/src/NumericalConstants.h | 1 + libraries/workload/src/workload/Space.h | 3 +- libraries/workload/src/workload/ViewTask.cpp | 56 +++++++++++++++----- libraries/workload/src/workload/ViewTask.h | 29 ++++++---- 5 files changed, 73 insertions(+), 30 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44bba6250b..0c25fd59a9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5795,15 +5795,13 @@ void Application::update(float deltaTime) { auto t5 = std::chrono::high_resolution_clock::now(); workload::Timings timings(6); - timings[0] = (t4 - t0); - timings[1] = (t5 - t4); - timings[2] = (t4 - t3); - timings[3] = (t3 - t2); - timings[4] = (t2 - t1); - timings[5] = (t1 - t0); - + timings[0] = t1 - t0; // prePhysics entities + timings[1] = t2 - t1; // prePhysics avatars + timings[2] = t3 - t2; // stepPhysics + timings[3] = t4 - t3; // postPhysics + timings[4] = t5 - t4; // non-physical kinematics + timings[5] = workload::Timing_ns((int32_t)(NSECS_PER_SECOND * deltaTime)); // game loop duration _gameWorkload.updateSimulationTimings(timings); - } } } else { diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index 4c24a73226..8377c48960 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -36,6 +36,7 @@ const float METERS_PER_MILLIMETER = 0.001f; const float MILLIMETERS_PER_METER = 1000.0f; const quint64 NSECS_PER_USEC = 1000; const quint64 NSECS_PER_MSEC = 1000000; +const quint64 NSECS_PER_SECOND = 1e9; const quint64 USECS_PER_MSEC = 1000; const quint64 MSECS_PER_SECOND = 1000; const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; diff --git a/libraries/workload/src/workload/Space.h b/libraries/workload/src/workload/Space.h index 310955f4c6..7dcb2217f7 100644 --- a/libraries/workload/src/workload/Space.h +++ b/libraries/workload/src/workload/Space.h @@ -70,7 +70,8 @@ private: using SpacePointer = std::shared_ptr; using Changes = std::vector; using IndexVectors = std::vector; -using Timings = std::vector; +using Timing_ns = std::chrono::nanoseconds; +using Timings = std::vector; } // namespace workload diff --git a/libraries/workload/src/workload/ViewTask.cpp b/libraries/workload/src/workload/ViewTask.cpp index 5d9953cdf4..b05a4c0c5f 100644 --- a/libraries/workload/src/workload/ViewTask.cpp +++ b/libraries/workload/src/workload/ViewTask.cpp @@ -102,9 +102,16 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const // Export the ranges and timings for debuging if (inTimings.size()) { - _dataExport.timings[workload::Region::R1] = std::chrono::duration(inTimings[0]).count(); + // NOTE for reference: + // inTimings[0] = prePhysics entities + // inTimings[1] = prePhysics avatars + // inTimings[2] = stepPhysics + // inTimings[3] = postPhysics + // inTimings[4] = non-physical kinematics + // inTimings[5] = game loop + _dataExport.timings[workload::Region::R1] = std::chrono::duration(inTimings[2] + inTimings[3]).count(); _dataExport.timings[workload::Region::R2] = _dataExport.timings[workload::Region::R1]; - _dataExport.timings[workload::Region::R3] = std::chrono::duration(inTimings[1]).count(); + _dataExport.timings[workload::Region::R3] = std::chrono::duration(inTimings[4]).count(); doExport = true; } @@ -115,11 +122,29 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const } } -glm::vec2 Regulator::run(const Timing_ns& regulationDuration, const Timing_ns& measured, const glm::vec2& current) { - // Regulate next value based on current moving toward the goal budget - float error_ms = std::chrono::duration(_budget - measured).count(); - float coef = glm::clamp(error_ms / std::chrono::duration(regulationDuration).count(), -1.0f, 1.0f); - return current * (1.0f + coef * (error_ms < 0.0f ? _relativeStepDown : _relativeStepUp)); +glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack) { + // measure signal: average and noise + const float FILTER_TIMESCALE = 0.5f * (float)NSECS_PER_SECOND; + float del = deltaTime.count() / FILTER_TIMESCALE; + if (del > 1.0f) { + del = 1.0f; // clamp for stability + } + _measuredTimeAverage = (1.0f - del) * _measuredTimeAverage + del * measuredTime.count(); + float diff = measuredTime.count() - _measuredTimeAverage; + _measuredTimeNoiseSquared = (1.0f - del) * _measuredTimeNoiseSquared + del * diff * diff; + float noise = sqrtf(_measuredTimeNoiseSquared); + + // check budget + float budgetDelta = _budget.count() - _measuredTimeAverage; + if (abs(budgetDelta) < noise) { + // budget is within the noise + return currentFrontBack; + } + + // clamp the step factor + del = budgetDelta < 0.0f ? -_relativeStepDown: _relativeStepUp; + + return currentFrontBack * (1.0f + del); } glm::vec2 Regulator::clamp(const glm::vec2& backFront) const { @@ -128,17 +153,24 @@ glm::vec2 Regulator::clamp(const glm::vec2& backFront) const { } void ControlViews::regulateViews(workload::Views& outViews, const workload::Timings& timings) { - for (auto& outView : outViews) { for (int32_t r = 0; r < workload::Region::NUM_VIEW_REGIONS; r++) { outView.regionBackFronts[r] = regionBackFronts[r]; } } - auto loopDuration = std::chrono::nanoseconds{ std::chrono::milliseconds(16) }; - regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[0], regionBackFronts[workload::Region::R1]); - regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[0], regionBackFronts[workload::Region::R2]); - regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[1], regionBackFronts[workload::Region::R3]); + // Note: for reference: + // timings[0] = prePhysics entities + // timings[1] = prePhysics avatars + // timings[2] = stepPhysics + // timings[3] = postPhysics + // timings[4] = non-physical kinematics + // timings[5] = game loop + + auto loopDuration = timings[5]; + regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R1]); + regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R2]); + regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[4], regionBackFronts[workload::Region::R3]); enforceRegionContainment(); for (auto& outView : outViews) { diff --git a/libraries/workload/src/workload/ViewTask.h b/libraries/workload/src/workload/ViewTask.h index 4fdd7e0f4c..7c1e4944f5 100644 --- a/libraries/workload/src/workload/ViewTask.h +++ b/libraries/workload/src/workload/ViewTask.h @@ -37,8 +37,8 @@ namespace workload { { 250.0f, 16000.0f } }; - const float RELATIVE_STEP_DOWN = 0.05f; - const float RELATIVE_STEP_UP = 0.04f; + const float RELATIVE_STEP_DOWN = 0.11f; + const float RELATIVE_STEP_UP = 0.09f; class SetupViewsConfig : public Job::Config{ Q_OBJECT @@ -212,20 +212,31 @@ namespace workload { }; struct Regulator { - using Timing_ns = std::chrono::nanoseconds; - Timing_ns _budget{ std::chrono::milliseconds(2) }; glm::vec2 _minRange{ MIN_VIEW_BACK_FRONTS[0] }; glm::vec2 _maxRange{ MAX_VIEW_BACK_FRONTS[0] }; - glm::vec2 _relativeStepDown{ RELATIVE_STEP_DOWN }; glm::vec2 _relativeStepUp{ RELATIVE_STEP_UP }; - + Timing_ns _budget{ std::chrono::milliseconds(2) }; + float _measuredTimeAverage { 0.0f }; + float _measuredTimeNoiseSquared { 0.0f }; Regulator() {} - Regulator(const Timing_ns& budget_ns, const glm::vec2& minRange, const glm::vec2& maxRange, const glm::vec2& relativeStepDown, const glm::vec2& relativeStepUp) : - _budget(budget_ns), _minRange(minRange), _maxRange(maxRange), _relativeStepDown(relativeStepDown), _relativeStepUp(relativeStepUp) {} + Regulator(const Timing_ns& budget_ns, + const glm::vec2& minRange, + const glm::vec2& maxRange, + const glm::vec2& relativeStepDown, + const glm::vec2& relativeStepUp) : + _minRange(minRange), + _maxRange(maxRange), + _relativeStepDown(relativeStepDown), + _relativeStepUp(relativeStepUp), + _budget(budget_ns), + _measuredTimeAverage(budget_ns.count()), + _measuredTimeNoiseSquared(0.0f) + {} - glm::vec2 run(const Timing_ns& regulationDuration, const Timing_ns& measured, const glm::vec2& current); + void setBudget(const Timing_ns& budget) { _budget = budget; } + glm::vec2 run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack); glm::vec2 clamp(const glm::vec2& backFront) const; }; From a134357489173f6c34d9d1a9ee51faf9ba30a0c8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Aug 2018 11:37:19 -0700 Subject: [PATCH 15/61] fix compile typo --- libraries/workload/src/workload/ViewTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/workload/src/workload/ViewTask.cpp b/libraries/workload/src/workload/ViewTask.cpp index b05a4c0c5f..27b136d64e 100644 --- a/libraries/workload/src/workload/ViewTask.cpp +++ b/libraries/workload/src/workload/ViewTask.cpp @@ -142,9 +142,9 @@ glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTi } // clamp the step factor - del = budgetDelta < 0.0f ? -_relativeStepDown: _relativeStepUp; + glm::vec2 stepDelta = budgetDelta < 0.0f ? -_relativeStepDown : _relativeStepUp; - return currentFrontBack * (1.0f + del); + return currentFrontBack * (1.0f + stepDelta); } glm::vec2 Regulator::clamp(const glm::vec2& backFront) const { From 6cc31e7397c8de9361f44febc3aa91278f4730d2 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 29 Aug 2018 13:30:13 -0700 Subject: [PATCH 16/61] AVX2 implementation of biquad2_4x4() --- libraries/audio/src/AudioHRTF.cpp | 6 ++- libraries/audio/src/avx2/AudioHRTF_avx2.cpp | 45 +++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 7895a70595..0f87df2346 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -457,8 +457,12 @@ static void interleave_4x4(float* src0, float* src1, float* src2, float* src3, f interleave_4x4_SSE(src0, src1, src2, src3, dst, numFrames); } +void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames); + static void biquad2_4x4(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { - biquad2_4x4_SSE(src, dst, coef, state, numFrames); + + static auto f = cpuSupportsAVX2() ? biquad2_4x4_AVX2 : biquad2_4x4_SSE; + (*f)(src, dst, coef, state, numFrames); // dispatch } static void crossfade_4x2(float* src, float* dst, const float* win, int numFrames) { diff --git a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp index 501f010236..0c3c6b5096 100644 --- a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp +++ b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp @@ -87,4 +87,49 @@ void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3 _mm256_zeroupper(); } +// process 2 cascaded biquads on 4 channels (interleaved) +// biquads are computed in parallel, by adding one sample of delay +void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { + + // enable flush-to-zero mode to prevent denormals + unsigned int ftz = _MM_GET_FLUSH_ZERO_MODE(); + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + + // restore state + __m256 x0 = _mm256_setzero_ps(); + __m256 y0 = _mm256_loadu_ps(state[0]); + __m256 w1 = _mm256_loadu_ps(state[1]); + __m256 w2 = _mm256_loadu_ps(state[2]); + + // biquad coefs + __m256 b0 = _mm256_loadu_ps(coef[0]); + __m256 b1 = _mm256_loadu_ps(coef[1]); + __m256 b2 = _mm256_loadu_ps(coef[2]); + __m256 a1 = _mm256_loadu_ps(coef[3]); + __m256 a2 = _mm256_loadu_ps(coef[4]); + + for (int i = 0; i < numFrames; i++) { + + // x0 = (first biquad output << 128) | input + x0 = _mm256_insertf128_ps(_mm256_permute2f128_ps(y0, y0, 0x01), _mm_loadu_ps(&src[4*i]), 0); + + // transposed Direct Form II + y0 = _mm256_fmadd_ps(x0, b0, w1); + w1 = _mm256_fmadd_ps(x0, b1, w2); + w2 = _mm256_mul_ps(x0, b2); + w1 = _mm256_fnmadd_ps(y0, a1, w1); + w2 = _mm256_fnmadd_ps(y0, a2, w2); + + _mm_storeu_ps(&dst[4*i], _mm256_extractf128_ps(y0, 1)); // second biquad output + } + + // save state + _mm256_storeu_ps(state[0], y0); + _mm256_storeu_ps(state[1], w1); + _mm256_storeu_ps(state[2], w2); + + _MM_SET_FLUSH_ZERO_MODE(ftz); + _mm256_zeroupper(); +} + #endif From 0981f08b22c5f04094428a84d8faeddbdf8b3347 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 29 Aug 2018 14:48:27 -0700 Subject: [PATCH 17/61] 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 18/61] 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 19/61] 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 20/61] 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 21/61] 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 22/61] 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 248c2621a43a6b9dc67e9d6002f7aa7f77e769e4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 29 Aug 2018 17:57:54 -0700 Subject: [PATCH 23/61] fix blendshapes crash --- .../render-utils/src/CauterizedModel.cpp | 5 +- libraries/render-utils/src/Model.cpp | 87 +++++++++---------- libraries/render-utils/src/Model.h | 2 + 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 3966d04b6d..259036f500 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -86,9 +86,8 @@ void CauterizedModel::createRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - if (!fbxGeometry.meshes[i].blendshapes.empty() && !_blendedVertexBuffers[i]) { - _blendedVertexBuffers[i] = std::make_shared(); - _blendedVertexBuffers[i]->resize(fbxGeometry.meshes[i].vertices.size() * (sizeof(glm::vec3) + 2 * sizeof(NormalType))); + if (!fbxGeometry.meshes[i].blendshapes.empty()) { + initializeBlendshapes(fbxGeometry.meshes[i], i); } auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::static_pointer_cast(ptr); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 71250c6483..946275a312 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -302,52 +302,11 @@ bool Model::updateGeometry() { assert(_meshStates.empty()); const FBXGeometry& fbxGeometry = getFBXGeometry(); - int i = 0; foreach (const FBXMesh& mesh, fbxGeometry.meshes) { MeshState state; state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size()); _meshStates.push_back(state); - - if (!mesh.blendshapes.isEmpty()) { - if (!_blendedVertexBuffers[i]) { - _blendedVertexBuffers[i] = std::make_shared(); - } - const auto& buffer = _blendedVertexBuffers[i]; - QVector normalsAndTangents; - normalsAndTangents.resize(2 * mesh.normals.size()); - - // Interleave normals and tangents - // Parallel version for performance - tbb::parallel_for(tbb::blocked_range(0, mesh.normals.size()), [&](const tbb::blocked_range& range) { - auto normalsRange = std::make_pair(mesh.normals.begin() + range.begin(), mesh.normals.begin() + range.end()); - auto tangentsRange = std::make_pair(mesh.tangents.begin() + range.begin(), mesh.tangents.begin() + range.end()); - auto normalsAndTangentsIt = normalsAndTangents.begin() + 2 * range.begin(); - - for (auto normalIt = normalsRange.first, tangentIt = tangentsRange.first; - normalIt != normalsRange.second; - ++normalIt, ++tangentIt) { -#if FBX_PACK_NORMALS - glm::uint32 finalNormal; - glm::uint32 finalTangent; - buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent); -#else - const auto& finalNormal = *normalIt; - const auto& finalTangent = *tangentIt; -#endif - *normalsAndTangentsIt = finalNormal; - ++normalsAndTangentsIt; - *normalsAndTangentsIt = finalTangent; - ++normalsAndTangentsIt; - } - }); - const auto verticesSize = mesh.vertices.size() * sizeof(glm::vec3); - buffer->resize(mesh.vertices.size() * sizeof(glm::vec3) + normalsAndTangents.size() * sizeof(NormalType)); - buffer->setSubData(0, verticesSize, (const gpu::Byte*) mesh.vertices.constData()); - buffer->setSubData(verticesSize, 2 * mesh.normals.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data()); - mesh.normalsAndTangents = normalsAndTangents; - } - i++; } needFullUpdate = true; emit rigReady(); @@ -1514,10 +1473,10 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo assert(buffer); buffer->resize(mesh.vertices.size() * sizeof(glm::vec3) + mesh.normalsAndTangents.size() * sizeof(NormalType)); buffer->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + index * sizeof(glm::vec3)); - buffer->setSubData(verticesSize, 2 * mesh.normals.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType)); + buffer->setSubData(verticesSize, mesh.normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType)); index += vertexCount; - normalAndTangentIndex += 2 * mesh.normals.size(); + normalAndTangentIndex += mesh.normalsAndTangents.size(); } } @@ -1555,6 +1514,42 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { return _modelMeshRenderItemIDs; } +void Model::initializeBlendshapes(const FBXMesh& mesh, int index) { + QVector normalsAndTangents; + normalsAndTangents.resize(2 * mesh.normals.size()); + + // Interleave normals and tangents + // Parallel version for performance + tbb::parallel_for(tbb::blocked_range(0, mesh.normals.size()), [&](const tbb::blocked_range& range) { + auto normalsRange = std::make_pair(mesh.normals.begin() + range.begin(), mesh.normals.begin() + range.end()); + auto tangentsRange = std::make_pair(mesh.tangents.begin() + range.begin(), mesh.tangents.begin() + range.end()); + auto normalsAndTangentsIt = normalsAndTangents.begin() + 2 * range.begin(); + + for (auto normalIt = normalsRange.first, tangentIt = tangentsRange.first; + normalIt != normalsRange.second; + ++normalIt, ++tangentIt) { +#if FBX_PACK_NORMALS + glm::uint32 finalNormal; + glm::uint32 finalTangent; + buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent); +#else + const auto& finalNormal = *normalIt; + const auto& finalTangent = *tangentIt; +#endif + *normalsAndTangentsIt = finalNormal; + ++normalsAndTangentsIt; + *normalsAndTangentsIt = finalTangent; + ++normalsAndTangentsIt; + } + }); + const auto verticesSize = mesh.vertices.size() * sizeof(glm::vec3); + _blendedVertexBuffers[index] = std::make_shared(); + _blendedVertexBuffers[index]->resize(mesh.vertices.size() * sizeof(glm::vec3) + normalsAndTangents.size() * sizeof(NormalType)); + _blendedVertexBuffers[index]->setSubData(0, verticesSize, (const gpu::Byte*) mesh.vertices.constData()); + _blendedVertexBuffers[index]->setSubData(verticesSize, normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data()); + mesh.normalsAndTangents = normalsAndTangents; +} + void Model::createRenderItemSet() { assert(isLoaded()); const auto& meshes = _renderGeometry->getMeshes(); @@ -1583,7 +1578,7 @@ void Model::createRenderItemSet() { // Run through all of the meshes, and place them into their segregated, but unsorted buckets int shapeID = 0; uint32_t numMeshes = (uint32_t)meshes.size(); - auto fbxGeometry = getFBXGeometry(); + auto& fbxGeometry = getFBXGeometry(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); if (!mesh) { @@ -1593,8 +1588,8 @@ void Model::createRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - if (fbxGeometry.meshes[i].blendshapes.empty() && !_blendedVertexBuffers[i]) { - _blendedVertexBuffers[i] = std::make_shared(); + if (!fbxGeometry.meshes[i].blendshapes.empty()) { + initializeBlendshapes(fbxGeometry.meshes[i], i); } _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); auto material = getGeometry()->getShapeMaterial(shapeID); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 677be61261..eaca068c10 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -482,6 +482,8 @@ protected: bool shouldInvalidatePayloadShapeKey(int meshIndex); + void initializeBlendshapes(const FBXMesh& mesh, int index); + private: float _loadingPriority { 0.0f }; From 6583864597136a7b41ab7abe0613b825333510b7 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 29 Aug 2018 19:19:20 -0700 Subject: [PATCH 24/61] AVX2 implementation of interleave_4x4() --- libraries/audio/src/AudioHRTF.cpp | 6 +++- libraries/audio/src/avx2/AudioHRTF_avx2.cpp | 37 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 0f87df2346..655527a65c 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -453,8 +453,12 @@ static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* ds (*f)(src, dst0, dst1, dst2, dst3, coef, numFrames); // dispatch } +void interleave_4x4_AVX2(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames); + static void interleave_4x4(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames) { - interleave_4x4_SSE(src0, src1, src2, src3, dst, numFrames); + + static auto f = cpuSupportsAVX2() ? interleave_4x4_AVX2 : interleave_4x4_SSE; + (*f)(src0, src1, src2, src3, dst, numFrames); // dispatch } void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames); diff --git a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp index 0c3c6b5096..9000df367f 100644 --- a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp +++ b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp @@ -87,6 +87,43 @@ void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3 _mm256_zeroupper(); } +// 4 channel planar to interleaved +void interleave_4x4_AVX2(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames) { + + assert(numFrames % 8 == 0); + + for (int i = 0; i < numFrames; i += 8) { + + __m256 x0 = _mm256_loadu_ps(&src0[i]); + __m256 x1 = _mm256_loadu_ps(&src1[i]); + __m256 x2 = _mm256_loadu_ps(&src2[i]); + __m256 x3 = _mm256_loadu_ps(&src3[i]); + + // interleave (4x4 matrix transpose) + __m256 t0 = _mm256_unpacklo_ps(x0, x1); + __m256 t1 = _mm256_unpackhi_ps(x0, x1); + __m256 t2 = _mm256_unpacklo_ps(x2, x3); + __m256 t3 = _mm256_unpackhi_ps(x2, x3); + + x0 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(1,0,1,0)); + x1 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(3,2,3,2)); + x2 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(1,0,1,0)); + x3 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(3,2,3,2)); + + t0 = _mm256_permute2f128_ps(x0, x1, 0x20); + t1 = _mm256_permute2f128_ps(x2, x3, 0x20); + t2 = _mm256_permute2f128_ps(x0, x1, 0x31); + t3 = _mm256_permute2f128_ps(x2, x3, 0x31); + + _mm256_storeu_ps(&dst[4*i+0], t0); + _mm256_storeu_ps(&dst[4*i+8], t1); + _mm256_storeu_ps(&dst[4*i+16], t2); + _mm256_storeu_ps(&dst[4*i+24], t3); + } + + _mm256_zeroupper(); +} + // process 2 cascaded biquads on 4 channels (interleaved) // biquads are computed in parallel, by adding one sample of delay void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { From a4bb8cb6221747730b27cf6de3ca6e7f41567255 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 30 Aug 2018 09:08:02 -0700 Subject: [PATCH 25/61] 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 6c4862910e70fe0236b8ce9e4539a03c205fe802 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Aug 2018 10:13:35 -0700 Subject: [PATCH 26/61] smoother edges for workload region feedback response --- libraries/workload/src/workload/ViewTask.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/workload/src/workload/ViewTask.cpp b/libraries/workload/src/workload/ViewTask.cpp index 27b136d64e..9d0c693149 100644 --- a/libraries/workload/src/workload/ViewTask.cpp +++ b/libraries/workload/src/workload/ViewTask.cpp @@ -135,15 +135,15 @@ glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTi float noise = sqrtf(_measuredTimeNoiseSquared); // check budget - float budgetDelta = _budget.count() - _measuredTimeAverage; - if (abs(budgetDelta) < noise) { - // budget is within the noise + float offsetFromTarget = _budget.count() - _measuredTimeAverage; + if (fabsf(offsetFromTarget) < noise) { + // budget is within the noise --> do nothing return currentFrontBack; } - // clamp the step factor - glm::vec2 stepDelta = budgetDelta < 0.0f ? -_relativeStepDown : _relativeStepUp; - + // compute response + glm::vec2 stepDelta = offsetFromTarget < 0.0f ? -_relativeStepDown : _relativeStepUp; + stepDelta *= glm::min(1.0f, (fabsf(offsetFromTarget) - noise) / noise); // ease out of "do nothing" return currentFrontBack * (1.0f + stepDelta); } From 4b7ca76ebdecd76950acb7b2f0daecc174a397bd Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 30 Aug 2018 14:15:57 -0700 Subject: [PATCH 27/61] Create correct folder. --- libraries/shared/src/shared/FileUtils.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/shared/FileUtils.cpp b/libraries/shared/src/shared/FileUtils.cpp index 9bdd65bf11..0709a53602 100644 --- a/libraries/shared/src/shared/FileUtils.cpp +++ b/libraries/shared/src/shared/FileUtils.cpp @@ -156,10 +156,12 @@ bool FileUtils::canCreateFile(const QString& fullPath) { qDebug(shared) << "unable to overwrite file '" << fullPath << "'"; return false; } - QDir dir(fileInfo.absolutePath()); + + QString absolutePath = fileInfo.absolutePath(); + QDir dir(absolutePath); if (!dir.exists()) { - if (!dir.mkpath(fullPath)) { - qDebug(shared) << "unable to create dir '" << dir.absolutePath() << "'"; + if (!dir.mkpath(absolutePath)) { + qDebug(shared) << "unable to create dir '" << absolutePath << "'"; return false; } } From 0f6fdef9284c95bc8a68e031bca7796618ec519d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 30 Aug 2018 15:06:05 -0700 Subject: [PATCH 28/61] Fixed compilation error (within #ifdef) --- libraries/fbx/src/OBJReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 501fb72130..c46a1e234c 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -273,7 +273,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { " diffuse texture:" << currentMaterial.diffuseTextureFilename << " specular texture:" << currentMaterial.specularTextureFilename << " emissive texture:" << currentMaterial.emissiveTextureFilename << - " bump texture:" << currentMaterial.bumpTextureFilename; + " bump texture:" << currentMaterial.bumpTextureFilename << " opacity texture:" << currentMaterial.opacityTextureFilename; #endif return; From 5f08ed5027a8904242a47b17e994ab4f309e3930 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 30 Aug 2018 15:13:52 -0700 Subject: [PATCH 29/61] misc perf improvements --- .../src/avatars/AvatarMixerSlave.cpp | 6 +- interface/src/avatar/AvatarManager.cpp | 23 +++----- interface/src/avatar/OtherAvatar.cpp | 9 ++- .../src/controllers/UserInputMapper.cpp | 6 +- .../src/EntityTreeRenderer.cpp | 9 ++- .../graphics/src/graphics/BufferViewHelpers.h | 5 +- libraries/shared/src/AABox.cpp | 56 ++++--------------- libraries/shared/src/AABox.h | 17 +++++- libraries/shared/src/GLMHelpers.h | 8 +++ libraries/shared/src/PrioritySortUtil.h | 15 +++-- tests/shared/src/AACubeTests.cpp | 2 +- tests/shared/src/GLMHelpersTests.cpp | 36 ++++++++++++ tests/shared/src/GLMHelpersTests.h | 1 + 13 files changed, 108 insertions(+), 85 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index f347ff1f10..59c6db5dc4 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -429,9 +429,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) int remainingAvatars = (int)sortedAvatars.size(); auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true); - while (!sortedAvatars.empty()) { - const auto avatarData = sortedAvatars.top().getAvatar(); - sortedAvatars.pop(); + const auto& sortedAvatarVector = sortedAvatars.getSortedVector(); + for (const auto& sortedAvatar : sortedAvatarVector) { + const auto& avatarData = sortedAvatar.getAvatar(); remainingAvatars--; auto otherNode = avatarDataToNodes[avatarData]; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 9a7d8ef0c8..af9d9ad6b1 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -206,6 +206,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } ++itr; } + const auto& sortedAvatarVector = sortedAvatars.getSortedVector(); // process in sorted order uint64_t startTime = usecTimestampNow(); @@ -216,8 +217,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { render::Transaction renderTransaction; workload::Transaction workloadTransaction; - while (!sortedAvatars.empty()) { - const SortableAvatar& sortData = sortedAvatars.top(); + for (auto it = sortedAvatarVector.begin(); it != sortedAvatarVector.end(); ++it) { + const SortableAvatar& sortData = *it; const auto avatar = std::static_pointer_cast(sortData.getAvatar()); // TODO: to help us scale to more avatars it would be nice to not have to poll orb state here @@ -231,7 +232,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); if (ignoring) { - sortedAvatars.pop(); continue; } @@ -260,26 +260,17 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { // --> some avatar velocity measurements may be a little off // no time to simulate, but we take the time to count how many were tragically missed - bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD; - if (!inView) { - break; - } - if (inView && avatar->hasNewJointData()) { - numAVatarsNotUpdated++; - } - sortedAvatars.pop(); - while (inView && !sortedAvatars.empty()) { - const SortableAvatar& newSortData = sortedAvatars.top(); + while (it != sortedAvatarVector.end()) { + const SortableAvatar& newSortData = *it; const auto newAvatar = std::static_pointer_cast(newSortData.getAvatar()); - inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD; + bool inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD; if (inView && newAvatar->hasNewJointData()) { numAVatarsNotUpdated++; } - sortedAvatars.pop(); + ++it; } break; } - sortedAvatars.pop(); } if (_shouldRender) { diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 29ad5aed91..a0fa496c4c 100644 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -29,20 +29,23 @@ OtherAvatar::~OtherAvatar() { } void OtherAvatar::removeOrb() { - if (qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) { + if (!_otherAvatarOrbMeshPlaceholderID.isNull()) { qApp->getOverlays().deleteOverlay(_otherAvatarOrbMeshPlaceholderID); + _otherAvatarOrbMeshPlaceholderID = UNKNOWN_OVERLAY_ID; } } void OtherAvatar::updateOrbPosition() { if (_otherAvatarOrbMeshPlaceholder != nullptr) { _otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition()); + if (_otherAvatarOrbMeshPlaceholderID.isNull()) { + _otherAvatarOrbMeshPlaceholderID = qApp->getOverlays().addOverlay(_otherAvatarOrbMeshPlaceholder); + } } } void OtherAvatar::createOrb() { - if (_otherAvatarOrbMeshPlaceholderID == UNKNOWN_OVERLAY_ID || - !qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) { + if (_otherAvatarOrbMeshPlaceholderID.isNull()) { _otherAvatarOrbMeshPlaceholder = std::make_shared(); _otherAvatarOrbMeshPlaceholder->setAlpha(1.0f); _otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF }); diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 371deec7d5..307064c073 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -527,8 +527,8 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) { } // If the source hasn't been written yet, defer processing of this route - auto source = route->source; - auto sourceInput = source->getInput(); + auto& source = route->source; + auto& sourceInput = source->getInput(); if (sourceInput.device == STANDARD_DEVICE && !force && source->writeable()) { if (debugRoutes && route->debug) { qCDebug(controllers) << "Source not yet written, deferring"; @@ -559,7 +559,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) { return true; } - auto destination = route->destination; + auto& destination = route->destination; // THis could happen if the route destination failed to create // FIXME: Maybe do not create the route if the destination failed and avoid this case ? if (!destination) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c3c4095251..a363093083 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -405,11 +405,14 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene // process the sorted renderables size_t numSorted = sortedRenderables.size(); - while (!sortedRenderables.empty() && usecTimestampNow() < expiry) { - const auto renderable = sortedRenderables.top().getRenderer(); + const auto& sortedRenderablesVector = sortedRenderables.getSortedVector(); + for (const auto& sortedRenderable : sortedRenderablesVector) { + if (usecTimestampNow() > expiry) { + break; + } + const auto& renderable = sortedRenderable.getRenderer(); renderable->updateInScene(scene, transaction); _renderablesToUpdate.erase(renderable->getEntity()->getID()); - sortedRenderables.pop(); } // compute average per-renderable update cost diff --git a/libraries/graphics/src/graphics/BufferViewHelpers.h b/libraries/graphics/src/graphics/BufferViewHelpers.h index a9707c3128..7c37c75163 100644 --- a/libraries/graphics/src/graphics/BufferViewHelpers.h +++ b/libraries/graphics/src/graphics/BufferViewHelpers.h @@ -13,6 +13,7 @@ #include #include "GpuHelpers.h" +#include "GLMHelpers.h" namespace graphics { class Mesh; @@ -55,8 +56,8 @@ namespace buffer_helpers { tangent = glm::clamp(tangent, -1.0f, 1.0f); normal *= 511.0f; tangent *= 511.0f; - normal = glm::round(normal); - tangent = glm::round(tangent); + normal = fastRoundf(normal); + tangent = fastRoundf(tangent); glm::detail::i10i10i10i2 normalStruct; glm::detail::i10i10i10i2 tangentStruct; diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index b4384c494f..e537c3e56a 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -79,33 +79,23 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& scale) { glm::vec3 AABox::getFarthestVertex(const glm::vec3& normal) const { glm::vec3 result = _corner; - if (normal.x > 0.0f) { - result.x += _scale.x; - } - if (normal.y > 0.0f) { - result.y += _scale.y; - } - if (normal.z > 0.0f) { - result.z += _scale.z; - } + float blend = (float)(normal.x > 0.0f); + result.x += blend * _scale.x + (1.0f - blend) * 0.0f; + blend = (float)(normal.y > 0.0f); + result.y += blend * _scale.y + (1.0f - blend) * 0.0f; + blend = (float)(normal.z > 0.0f); + result.z += blend * _scale.z + (1.0f - blend) * 0.0f; return result; } glm::vec3 AABox::getNearestVertex(const glm::vec3& normal) const { glm::vec3 result = _corner; - - if (normal.x < 0.0f) { - result.x += _scale.x; - } - - if (normal.y < 0.0f) { - result.y += _scale.y; - } - - if (normal.z < 0.0f) { - result.z += _scale.z; - } - + float blend = (float)(normal.x < 0.0f); + result.x += blend * _scale.x + (1.0f - blend) * 0.0f; + blend = (float)(normal.y < 0.0f); + result.y += blend * _scale.y + (1.0f - blend) * 0.0f; + blend = (float)(normal.z < 0.0f); + result.z += blend * _scale.z + (1.0f - blend) * 0.0f; return result; } @@ -459,28 +449,6 @@ AABox AABox::clamp(float min, float max) const { return AABox(clampedCorner, clampedScale); } -AABox& AABox::operator += (const glm::vec3& point) { - - if (isInvalid()) { - _corner = glm::min(_corner, point); - } else { - glm::vec3 maximum(_corner + _scale); - _corner = glm::min(_corner, point); - maximum = glm::max(maximum, point); - _scale = maximum - _corner; - } - - return (*this); -} - -AABox& AABox::operator += (const AABox& box) { - if (!box.isInvalid()) { - (*this) += box._corner; - (*this) += box.calcTopFarLeft(); - } - return (*this); -} - void AABox::embiggen(float scale) { _corner += scale * (-0.5f * _scale); _scale *= scale; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index daad01d7c7..a56615c40e 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -85,8 +85,21 @@ public: AABox clamp(const glm::vec3& min, const glm::vec3& max) const; AABox clamp(float min, float max) const; - AABox& operator += (const glm::vec3& point); - AABox& operator += (const AABox& box); + inline AABox& operator+=(const glm::vec3& point) { + float blend = (float)isInvalid(); + glm::vec3 maximumScale(glm::max(_scale, point - _corner)); + _corner = glm::min(_corner, point); + _scale = blend * _scale + (1.0f - blend) * maximumScale; + return (*this); + } + + inline AABox& operator+=(const AABox& box) { + if (!box.isInvalid()) { + (*this) += box._corner; + (*this) += box.calcTopFarLeft(); + } + return (*this); + } // Translate the AABox just moving the corner void translate(const glm::vec3& translation) { _corner += translation; } diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 7e6ef4cb28..619f8172d5 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -316,4 +316,12 @@ inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r #endif } +inline glm::vec3 fastRoundf(const glm::vec3& vec) { +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + return glm::vec3(_mm_cvt_ss2si(_mm_set_ss(vec.x)), _mm_cvt_ss2si(_mm_set_ss(vec.y)), _mm_cvt_ss2si(_mm_set_ss(vec.z))); +#else + return glm::round(vec); +#endif +} + #endif // hifi_GLMHelpers_h diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index 34ec074d45..e0137b3d8c 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -12,7 +12,6 @@ #define hifi_PrioritySortUtil_h #include -#include #include "NumericalConstants.h" #include "shared/ConicalViewFrustum.h" @@ -75,7 +74,6 @@ namespace PrioritySortUtil { void setPriority(float priority) { _priority = priority; } float getPriority() const { return _priority; } - bool operator<(const Sortable& other) const { return _priority < other._priority; } private: float _priority { 0.0f }; }; @@ -97,14 +95,15 @@ namespace PrioritySortUtil { _ageWeight = ageWeight; } - size_t size() const { return _queue.size(); } + size_t size() const { return _vector.size(); } void push(T thing) { thing.setPriority(computePriority(thing)); - _queue.push(thing); + _vector.push_back(thing); + } + const std::vector& getSortedVector() { + std::sort(_vector.begin(), _vector.end(), [](const T& left, const T& right) { return left.getPriority() > right.getPriority(); }); + return _vector; } - const T& top() const { return _queue.top(); } - void pop() { return _queue.pop(); } - bool empty() const { return _queue.empty(); } private: @@ -153,7 +152,7 @@ namespace PrioritySortUtil { } ConicalViewFrustums _views; - std::priority_queue _queue; + std::vector _vector; float _angularWeight { DEFAULT_ANGULAR_COEF }; float _centerWeight { DEFAULT_CENTER_COEF }; float _ageWeight { DEFAULT_AGE_COEF }; diff --git a/tests/shared/src/AACubeTests.cpp b/tests/shared/src/AACubeTests.cpp index 95a4d7f9f0..c3c8e3e6f7 100644 --- a/tests/shared/src/AACubeTests.cpp +++ b/tests/shared/src/AACubeTests.cpp @@ -173,7 +173,7 @@ void AACubeTests::rayVsParabolaPerformance() { glm::vec3 normal; auto start = std::chrono::high_resolution_clock::now(); for (auto& cube : cubes) { - if (cube.findRayIntersection(origin, direction, distance, face, normal)) { + if (cube.findRayIntersection(origin, direction, 1.0f / direction, distance, face, normal)) { numRayHits++; } } diff --git a/tests/shared/src/GLMHelpersTests.cpp b/tests/shared/src/GLMHelpersTests.cpp index 93c4735a6d..669bbb8e43 100644 --- a/tests/shared/src/GLMHelpersTests.cpp +++ b/tests/shared/src/GLMHelpersTests.cpp @@ -214,3 +214,39 @@ void GLMHelpersTests::testGenerateBasisVectors() { QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON); } } + +void GLMHelpersTests::roundPerf() { + const int NUM_VECS = 1000000; + const float MAX_VEC = 500.0f; + std::vector vecs; + vecs.reserve(NUM_VECS); + for (int i = 0; i < NUM_VECS; i++) { + vecs.emplace_back(randFloatInRange(-MAX_VEC, MAX_VEC), randFloatInRange(-MAX_VEC, MAX_VEC), randFloatInRange(-MAX_VEC, MAX_VEC)); + } + std::vector vecs2 = vecs; + std::vector originalVecs = vecs; + + auto start = std::chrono::high_resolution_clock::now(); + for (auto& vec : vecs) { + vec = glm::round(vec); + } + + auto glmTime = std::chrono::high_resolution_clock::now() - start; + start = std::chrono::high_resolution_clock::now(); + for (auto& vec : vecs2) { + vec = fastRoundf(vec); + } + auto manualTime = std::chrono::high_resolution_clock::now() - start; + + bool identical = true; + for (int i = 0; i < vecs.size(); i++) { + identical &= vecs[i] == vecs2[i]; + if (vecs[i] != vecs2[i]) { + qDebug() << "glm: " << vecs[i].x << vecs[i].y << vecs[i].z << ", manual: " << vecs2[i].x << vecs2[i].y << vecs2[i].z; + qDebug() << "original: " << originalVecs[i].x << originalVecs[i].y << originalVecs[i].z; + break; + } + } + + qDebug() << "ratio: " << (float)glmTime.count() / (float)manualTime.count() << ", identical: " << identical; +} \ No newline at end of file diff --git a/tests/shared/src/GLMHelpersTests.h b/tests/shared/src/GLMHelpersTests.h index 030f2d477f..4d9bd0bb60 100644 --- a/tests/shared/src/GLMHelpersTests.h +++ b/tests/shared/src/GLMHelpersTests.h @@ -22,6 +22,7 @@ private slots: void testSixByteOrientationCompression(); void testSimd(); void testGenerateBasisVectors(); + void roundPerf(); }; float getErrorDifference(const float& a, const float& b); From e94d7de99afb4f8914150a9cca3cc524d4fa8503 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 30 Aug 2018 16:05:25 -0700 Subject: [PATCH 30/61] 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 31/61] 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 32/61] 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 33/61] 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 34/61] 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 35/61] 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 36/61] 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. */ From d01b438cb320a7ccc0aa8a0085e86940bb73c09c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 31 Aug 2018 11:25:17 -0700 Subject: [PATCH 37/61] CR --- interface/src/avatar/AvatarManager.cpp | 6 ++++-- .../graphics/src/graphics/BufferViewHelpers.h | 14 ++++++------- libraries/shared/src/AABox.cpp | 20 +++++++++++++++++++ libraries/shared/src/AABox.h | 9 +++++++++ libraries/shared/src/GLMHelpers.h | 11 +++++++--- tests/shared/src/AACubeTests.cpp | 3 ++- tests/shared/src/GLMHelpersTests.cpp | 2 +- 7 files changed, 50 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index af9d9ad6b1..bd98549510 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -264,9 +264,11 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const SortableAvatar& newSortData = *it; const auto newAvatar = std::static_pointer_cast(newSortData.getAvatar()); bool inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD; - if (inView && newAvatar->hasNewJointData()) { - numAVatarsNotUpdated++; + // Once we reach an avatar that's not in view, all avatars after it will also be out of view + if (!inView) { + break; } + numAVatarsNotUpdated += (int)(newAvatar->hasNewJointData()); ++it; } break; diff --git a/libraries/graphics/src/graphics/BufferViewHelpers.h b/libraries/graphics/src/graphics/BufferViewHelpers.h index 7c37c75163..026e7b53a3 100644 --- a/libraries/graphics/src/graphics/BufferViewHelpers.h +++ b/libraries/graphics/src/graphics/BufferViewHelpers.h @@ -56,18 +56,16 @@ namespace buffer_helpers { tangent = glm::clamp(tangent, -1.0f, 1.0f); normal *= 511.0f; tangent *= 511.0f; - normal = fastRoundf(normal); - tangent = fastRoundf(tangent); glm::detail::i10i10i10i2 normalStruct; glm::detail::i10i10i10i2 tangentStruct; - normalStruct.data.x = int(normal.x); - normalStruct.data.y = int(normal.y); - normalStruct.data.z = int(normal.z); + normalStruct.data.x = fastLrintf(normal.x); + normalStruct.data.y = fastLrintf(normal.y); + normalStruct.data.z = fastLrintf(normal.z); normalStruct.data.w = 0; - tangentStruct.data.x = int(tangent.x); - tangentStruct.data.y = int(tangent.y); - tangentStruct.data.z = int(tangent.z); + tangentStruct.data.x = fastLrintf(tangent.x); + tangentStruct.data.y = fastLrintf(tangent.y); + tangentStruct.data.z = fastLrintf(tangent.z); tangentStruct.data.w = 0; packedNormal = normalStruct.pack; packedTangent = tangentStruct.pack; diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index e537c3e56a..ff6c2a4e6e 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -79,6 +79,16 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& scale) { glm::vec3 AABox::getFarthestVertex(const glm::vec3& normal) const { glm::vec3 result = _corner; + // This is a branchless version of: + //if (normal.x > 0.0f) { + // result.x += _scale.x; + //} + //if (normal.y > 0.0f) { + // result.y += _scale.y; + //} + //if (normal.z > 0.0f) { + // result.z += _scale.z; + //} float blend = (float)(normal.x > 0.0f); result.x += blend * _scale.x + (1.0f - blend) * 0.0f; blend = (float)(normal.y > 0.0f); @@ -90,6 +100,16 @@ glm::vec3 AABox::getFarthestVertex(const glm::vec3& normal) const { glm::vec3 AABox::getNearestVertex(const glm::vec3& normal) const { glm::vec3 result = _corner; + // This is a branchless version of: + //if (normal.x < 0.0f) { + // result.x += _scale.x; + //} + //if (normal.y < 0.0f) { + // result.y += _scale.y; + //} + //if (normal.z < 0.0f) { + // result.z += _scale.z; + //} float blend = (float)(normal.x < 0.0f); result.x += blend * _scale.x + (1.0f - blend) * 0.0f; blend = (float)(normal.y < 0.0f); diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index a56615c40e..e0bb1343f8 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -86,6 +86,15 @@ public: AABox clamp(float min, float max) const; inline AABox& operator+=(const glm::vec3& point) { + // Branchless version of: + //if (isInvalid()) { + // _corner = glm::min(_corner, point); + //} else { + // glm::vec3 maximum(_corner + _scale); + // _corner = glm::min(_corner, point); + // maximum = glm::max(maximum, point); + // _scale = maximum - _corner; + //} float blend = (float)isInvalid(); glm::vec3 maximumScale(glm::max(_scale, point - _corner)); _corner = glm::min(_corner, point); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 619f8172d5..96219ea48c 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -316,11 +316,16 @@ inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r #endif } -inline glm::vec3 fastRoundf(const glm::vec3& vec) { +// convert float to int, using round-to-nearest-even (undefined on overflow) +inline int fastLrintf(float x) { #if GLM_ARCH & GLM_ARCH_SSE2_BIT - return glm::vec3(_mm_cvt_ss2si(_mm_set_ss(vec.x)), _mm_cvt_ss2si(_mm_set_ss(vec.y)), _mm_cvt_ss2si(_mm_set_ss(vec.z))); + return _mm_cvt_ss2si(_mm_set_ss(x)); #else - return glm::round(vec); + // return lrintf(x); + static_assert(std::numeric_limits::is_iec559, "Requires IEEE-754 double precision format"); + union { double d; int64_t i; } bits = { (double)x }; + bits.d += (3ULL << 51); + return (int)bits.i; #endif } diff --git a/tests/shared/src/AACubeTests.cpp b/tests/shared/src/AACubeTests.cpp index c3c8e3e6f7..4ed3ee2813 100644 --- a/tests/shared/src/AACubeTests.cpp +++ b/tests/shared/src/AACubeTests.cpp @@ -168,12 +168,13 @@ void AACubeTests::rayVsParabolaPerformance() { glm::vec3 origin(0.0f); glm::vec3 direction = glm::normalize(glm::vec3(1.0f)); + glm::vec3 invDirection = 1.0f / direction; float distance; BoxFace face; glm::vec3 normal; auto start = std::chrono::high_resolution_clock::now(); for (auto& cube : cubes) { - if (cube.findRayIntersection(origin, direction, 1.0f / direction, distance, face, normal)) { + if (cube.findRayIntersection(origin, direction, invDirection, distance, face, normal)) { numRayHits++; } } diff --git a/tests/shared/src/GLMHelpersTests.cpp b/tests/shared/src/GLMHelpersTests.cpp index 669bbb8e43..71877e89f6 100644 --- a/tests/shared/src/GLMHelpersTests.cpp +++ b/tests/shared/src/GLMHelpersTests.cpp @@ -234,7 +234,7 @@ void GLMHelpersTests::roundPerf() { auto glmTime = std::chrono::high_resolution_clock::now() - start; start = std::chrono::high_resolution_clock::now(); for (auto& vec : vecs2) { - vec = fastRoundf(vec); + vec = glm::vec3(fastLrintf(vec.x), fastLrintf(vec.y), fastLrintf(vec.z)); } auto manualTime = std::chrono::high_resolution_clock::now() - start; From 727bd6b05af29d3edd9b3d23a34428418e553712 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 31 Aug 2018 13:31:26 -0700 Subject: [PATCH 38/61] don't bid for simulation ownership of locked things --- libraries/physics/src/EntityMotionState.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 925cfee740..2c130274bc 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -778,8 +778,10 @@ void EntityMotionState::computeCollisionGroupAndMask(int32_t& group, int32_t& ma bool EntityMotionState::shouldSendBid() const { // NOTE: this method is only ever called when the entity's simulation is NOT locally owned - return _body->isActive() && (_region == workload::Region::R1) && - glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority(); + return _body->isActive() + && (_region == workload::Region::R1) + && glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority() + && !_entity->getLocked(); } uint8_t EntityMotionState::computeFinalBidPriority() const { From 028092f80398a1127da3bf019e59675b5192566c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 31 Aug 2018 13:33:45 -0700 Subject: [PATCH 39/61] fix blendshapes one last time --- libraries/render-utils/src/CauterizedModel.cpp | 4 ++-- libraries/render-utils/src/CauterizedModel.h | 2 +- libraries/render-utils/src/Model.cpp | 6 +++--- libraries/render-utils/src/Model.h | 2 +- libraries/render-utils/src/SoftAttachmentModel.cpp | 4 ++-- libraries/render-utils/src/SoftAttachmentModel.h | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 259036f500..2754697db7 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -102,7 +102,7 @@ void CauterizedModel::createRenderItemSet() { } } -void CauterizedModel::updateClusterMatrices() { +void CauterizedModel::updateClusterMatrices(bool triggerBlendshapes) { PerformanceTimer perfTimer("CauterizedModel::updateClusterMatrices"); if (!_needsUpdateClusterMatrices || !isLoaded()) { @@ -175,7 +175,7 @@ void CauterizedModel::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (triggerBlendshapes && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render-utils/src/CauterizedModel.h b/libraries/render-utils/src/CauterizedModel.h index 36a96fb006..12cf921e5b 100644 --- a/libraries/render-utils/src/CauterizedModel.h +++ b/libraries/render-utils/src/CauterizedModel.h @@ -33,7 +33,7 @@ public: void createRenderItemSet() override; - virtual void updateClusterMatrices() override; + virtual void updateClusterMatrices(bool triggerBlendshapes = true) override; void updateRenderItems() override; const Model::MeshState& getCauterizeMeshState(int index) const; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4158b14223..8287b9cca6 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -976,7 +976,7 @@ bool Model::addToScene(const render::ScenePointer& scene, render::Transaction& transaction, render::Item::Status::Getters& statusGetters) { if (!_addedToScene && isLoaded()) { - updateClusterMatrices(); + updateClusterMatrices(false); if (_modelMeshRenderItems.empty()) { createRenderItemSet(); } @@ -1486,7 +1486,7 @@ void Model::computeMeshPartLocalBounds() { } // virtual -void Model::updateClusterMatrices() { +void Model::updateClusterMatrices(bool triggerBlendshapes) { DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices"); if (!_needsUpdateClusterMatrices || !isLoaded()) { @@ -1515,7 +1515,7 @@ void Model::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (triggerBlendshapes && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4642515294..5ab50da162 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -159,7 +159,7 @@ public: bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } virtual void simulate(float deltaTime, bool fullUpdate = true); - virtual void updateClusterMatrices(); + virtual void updateClusterMatrices(bool triggerBlendshapes = true); /// Returns a reference to the shared geometry. const Geometry::Pointer& getGeometry() const { return _renderGeometry; } diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index f9b90f38ba..93ce8f595a 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -31,7 +31,7 @@ int SoftAttachmentModel::getJointIndexOverride(int i) const { // virtual // use the _rigOverride matrices instead of the Model::_rig -void SoftAttachmentModel::updateClusterMatrices() { +void SoftAttachmentModel::updateClusterMatrices(bool triggerBlendshapes) { if (!_needsUpdateClusterMatrices) { return; } @@ -78,7 +78,7 @@ void SoftAttachmentModel::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (triggerBlendshapes && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render-utils/src/SoftAttachmentModel.h b/libraries/render-utils/src/SoftAttachmentModel.h index 4335c1634e..03038c35f3 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.h +++ b/libraries/render-utils/src/SoftAttachmentModel.h @@ -27,7 +27,7 @@ public: ~SoftAttachmentModel(); void updateRig(float deltaTime, glm::mat4 parentTransform) override; - void updateClusterMatrices() override; + void updateClusterMatrices(bool triggerBlendshapes = true) override; protected: int getJointIndexOverride(int i) const; From 48680329ec4b29076179eeb04c882408d575d53f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Aug 2018 21:26:19 -0700 Subject: [PATCH 40/61] mark trait instances needing to be sent on mixer reconnect --- libraries/avatars/src/AvatarData.cpp | 12 +++++++++++- libraries/avatars/src/AvatarData.h | 2 ++ libraries/avatars/src/ClientTraitsHandler.cpp | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b86398501e..ea6dbd7074 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1895,6 +1895,16 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr return bytesWritten; } +void AvatarData::prepareResetTraitInstances() { + if (_clientTraitsHandler) { + _avatarEntitiesLock.withReadLock([this]{ + foreach (auto entityID, _avatarEntityData.keys()) { + _clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID); + } + }); + } +} + void AvatarData::processTrait(AvatarTraits::TraitType traitType, QByteArray traitBinaryData) { if (traitType == AvatarTraits::SkeletonModelURL) { // get the URL from the binary data @@ -2792,7 +2802,7 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { if (_clientTraitsHandler) { // if we have a client traits handler, flag any updated or created entities // so that we send changes for them next frame - foreach (auto entityID, _avatarEntityData) { + foreach (auto entityID, _avatarEntityData.keys()) { _clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID); } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 0474d07acd..db2b82b0b7 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -964,6 +964,8 @@ public: qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID, ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION); + void prepareResetTraitInstances(); + void processTrait(AvatarTraits::TraitType traitType, QByteArray traitBinaryData); void processTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData); diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index c4073cb86a..a06b53da7c 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -37,6 +37,12 @@ void ClientTraitsHandler::resetForNewMixer() { // mark that all traits should be sent next time _shouldPerformInitialSend = true; + + // reset the trait statuses + _traitStatuses.reset(); + + // pre-fill the instanced statuses that we will need to send next frame + _owningAvatar->prepareResetTraitInstances(); } void ClientTraitsHandler::sendChangedTraitsToMixer() { From 20912349a4f0b8854bda467ee1e1bd04d9bb67ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Aug 2018 12:59:28 -0700 Subject: [PATCH 41/61] cycle avatar entity IDs for new avatar mixer --- interface/src/Application.cpp | 1 - .../src/avatars-renderer/Avatar.cpp | 1 - libraries/avatars/src/AvatarData.cpp | 10 ++++++++-- libraries/avatars/src/AvatarData.h | 3 ++- libraries/avatars/src/AvatarTraits.h | 2 +- libraries/avatars/src/ClientTraitsHandler.cpp | 20 ++++++++++++++++++- libraries/avatars/src/ClientTraitsHandler.h | 8 ++++++-- 7 files changed, 36 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6e57311306..2a7abfa2da 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6366,7 +6366,6 @@ void Application::clearDomainOctreeDetails() { } void Application::clearDomainAvatars() { - getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities DependencyManager::get()->clearOtherAvatars(); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index a9af3b7725..4ffccefe61 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -139,7 +139,6 @@ Avatar::~Avatar() { } }); } - auto geometryCache = DependencyManager::get(); if (geometryCache) { geometryCache->releaseID(_nameRectGeometryID); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ea6dbd7074..e7aaa18576 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1861,7 +1861,9 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice } qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID traitInstanceID, - ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion) { + ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion, + AvatarTraits::TraitInstanceID wireInstanceID) { + qint64 bytesWritten = 0; bytesWritten += destination.writePrimitive(traitType); @@ -1870,7 +1872,11 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr bytesWritten += destination.writePrimitive(traitVersion); } - bytesWritten += destination.write(traitInstanceID.toRfc4122()); + if (!wireInstanceID.isNull()) { + bytesWritten += destination.write(wireInstanceID.toRfc4122()); + } else { + bytesWritten += destination.write(traitInstanceID.toRfc4122()); + } if (traitType == AvatarTraits::AvatarEntity) { // grab a read lock on the avatar entities and check for entity data for the given ID diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index db2b82b0b7..b010a9f924 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -962,7 +962,8 @@ public: qint64 packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION); qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID, - ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION); + ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION, + AvatarTraits::TraitInstanceID wireInstanceID = AvatarTraits::TraitInstanceID()); void prepareResetTraitInstances(); diff --git a/libraries/avatars/src/AvatarTraits.h b/libraries/avatars/src/AvatarTraits.h index f0c807a432..5866caf234 100644 --- a/libraries/avatars/src/AvatarTraits.h +++ b/libraries/avatars/src/AvatarTraits.h @@ -41,7 +41,7 @@ namespace AvatarTraits { const TraitWireSize DELETED_TRAIT_SIZE = -1; inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination, - TraitVersion traitVersion = NULL_TRAIT_VERSION) { + TraitVersion traitVersion = NULL_TRAIT_VERSION) { qint64 bytesWritten = 0; bytesWritten += destination.writePrimitive(traitType); diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index a06b53da7c..94823610dc 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -43,6 +43,9 @@ void ClientTraitsHandler::resetForNewMixer() { // pre-fill the instanced statuses that we will need to send next frame _owningAvatar->prepareResetTraitInstances(); + + // reset the trait XOR ID since we're resetting for a new avatar mixer + _sessionXORID = QUuid::createUuid().toRfc4122(); } void ClientTraitsHandler::sendChangedTraitsToMixer() { @@ -93,7 +96,11 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { || instanceIDValuePair.value == Updated) { // this is a changed trait we need to send or we haven't send out trait information yet // ask the owning avatar to pack it - _owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList); + + // since this is going to the mixer, use the XORed instance ID (to anonymize trait instance IDs + // that would typically persist across sessions) + _owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList, + AvatarTraits::NULL_TRAIT_VERSION, xorInstanceID(instanceIDValuePair.id)); } else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) { // pack delete for this trait instance AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id, @@ -111,6 +118,17 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { } } +AvatarTraits::TraitInstanceID ClientTraitsHandler::xorInstanceID(AvatarTraits::TraitInstanceID localInstanceID) { + QByteArray xorInstanceID { NUM_BYTES_RFC4122_UUID, 0 }; + auto localInstanceIDBytes = localInstanceID.toRfc4122(); + + for (auto i = 0; i < localInstanceIDBytes.size(); ++i) { + xorInstanceID[i] = localInstanceIDBytes[i] ^ _sessionXORID[i]; + } + + return QUuid::fromRfc4122(xorInstanceID); +} + void ClientTraitsHandler::processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode) { if (sendingNode->getType() == NodeType::AvatarMixer) { while (message->getBytesLeftToRead()) { diff --git a/libraries/avatars/src/ClientTraitsHandler.h b/libraries/avatars/src/ClientTraitsHandler.h index 27ba58d46b..2319061502 100644 --- a/libraries/avatars/src/ClientTraitsHandler.h +++ b/libraries/avatars/src/ClientTraitsHandler.h @@ -30,13 +30,15 @@ public: void markTraitUpdated(AvatarTraits::TraitType updatedTrait) { _traitStatuses[updatedTrait] = Updated; _hasChangedTraits = true; } - void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID) + void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID updatedInstanceID) { _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); _hasChangedTraits = true; } - void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID) + void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID deleteInstanceID) { _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); _hasChangedTraits = true; } void resetForNewMixer(); + AvatarTraits::TraitInstanceID xorInstanceID(AvatarTraits::TraitInstanceID localInstanceID); + public slots: void processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode); @@ -53,6 +55,8 @@ private: AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION }; AvatarTraits::TraitVersion _currentSkeletonVersion { AvatarTraits::NULL_TRAIT_VERSION }; + + QByteArray _sessionXORID { NUM_BYTES_RFC4122_UUID, 0}; bool _shouldPerformInitialSend { false }; bool _hasChangedTraits { false }; From 9b3d9dd0f319ad2964e54a72bd17934765a91c02 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Aug 2018 16:31:33 -0700 Subject: [PATCH 42/61] XOR incoming trait instance IDs for other avatars --- libraries/avatars/src/AvatarData.h | 5 +++++ libraries/avatars/src/AvatarHashMap.cpp | 20 ++++++++++++++---- libraries/avatars/src/AvatarTraits.h | 21 +++++++++++++++++-- libraries/avatars/src/ClientTraitsHandler.cpp | 21 +++++++------------ libraries/avatars/src/ClientTraitsHandler.h | 4 ---- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index b010a9f924..e9f1f5f6c3 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1193,6 +1193,9 @@ public: void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; } int getReplicaIndex() { return _replicaIndex; } + const AvatarTraits::TraitInstanceID getTraitInstanceXORID() const { return _traitInstanceXORID; } + void cycleTraitInstanceXORID() { _traitInstanceXORID = QUuid::createUuid(); } + signals: /**jsdoc @@ -1499,6 +1502,8 @@ private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); AvatarData& operator= (const AvatarData&); + + AvatarTraits::TraitInstanceID _traitInstanceXORID { QUuid::createUuid() }; }; Q_DECLARE_METATYPE(AvatarData*) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index c437b56f32..fac2af9ebc 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -335,17 +335,29 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess AvatarTraits::TraitInstanceID traitInstanceID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + // XOR the incoming trait instance ID with this avatar object's personal XOR ID + + // this ensures that we have separate entity instances in the local tree + // if we briefly end up with two Avatar objects for this node + + // (which can occur if the shared pointer for the + // previous instance of an avatar hasn't yet gone out of scope before the + // new instance is created) + + auto xoredInstanceID = AvatarTraits::xoredInstanceID(traitInstanceID, avatar->getTraitInstanceXORID()); + message->readPrimitive(&traitBinarySize); auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID); if (packetTraitVersion > processedInstanceVersion) { + // in order to handle re-connections to the avatar mixer when the other if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) { - avatar->processDeletedTraitInstance(traitType, traitInstanceID); - _replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID); + avatar->processDeletedTraitInstance(traitType, xoredInstanceID); + _replicas.processDeletedTraitInstance(avatarID, traitType, xoredInstanceID); } else { auto traitData = message->read(traitBinarySize); - avatar->processTraitInstance(traitType, traitInstanceID, traitData); - _replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData); + avatar->processTraitInstance(traitType, xoredInstanceID, traitData); + _replicas.processTraitInstance(avatarID, traitType, xoredInstanceID, traitData); } processedInstanceVersion = packetTraitVersion; } else { diff --git a/libraries/avatars/src/AvatarTraits.h b/libraries/avatars/src/AvatarTraits.h index 5866caf234..47be0d6111 100644 --- a/libraries/avatars/src/AvatarTraits.h +++ b/libraries/avatars/src/AvatarTraits.h @@ -41,7 +41,8 @@ namespace AvatarTraits { const TraitWireSize DELETED_TRAIT_SIZE = -1; inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination, - TraitVersion traitVersion = NULL_TRAIT_VERSION) { + TraitVersion traitVersion = NULL_TRAIT_VERSION, + TraitInstanceID xoredInstanceID = TraitInstanceID()) { qint64 bytesWritten = 0; bytesWritten += destination.writePrimitive(traitType); @@ -50,12 +51,28 @@ namespace AvatarTraits { bytesWritten += destination.writePrimitive(traitVersion); } - bytesWritten += destination.write(instanceID.toRfc4122()); + if (xoredInstanceID.isNull()) { + bytesWritten += destination.write(instanceID.toRfc4122()); + } else { + bytesWritten += destination.write(xoredInstanceID.toRfc4122()); + } bytesWritten += destination.writePrimitive(DELETED_TRAIT_SIZE); return bytesWritten; } + + inline TraitInstanceID xoredInstanceID(TraitInstanceID localInstanceID, TraitInstanceID xorKeyID) { + QByteArray xoredInstanceID { NUM_BYTES_RFC4122_UUID, 0 }; + auto xorKeyIDBytes = xorKeyID.toRfc4122(); + auto localInstanceIDBytes = localInstanceID.toRfc4122(); + + for (auto i = 0; i < localInstanceIDBytes.size(); ++i) { + xoredInstanceID[i] = localInstanceIDBytes[i] ^ xorKeyIDBytes[i]; + } + + return QUuid::fromRfc4122(xoredInstanceID); + } }; #endif // hifi_AvatarTraits_h diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index 94823610dc..479852cf9a 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -45,7 +45,7 @@ void ClientTraitsHandler::resetForNewMixer() { _owningAvatar->prepareResetTraitInstances(); // reset the trait XOR ID since we're resetting for a new avatar mixer - _sessionXORID = QUuid::createUuid().toRfc4122(); + _owningAvatar->cycleTraitInstanceXORID(); } void ClientTraitsHandler::sendChangedTraitsToMixer() { @@ -100,11 +100,15 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { // since this is going to the mixer, use the XORed instance ID (to anonymize trait instance IDs // that would typically persist across sessions) _owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList, - AvatarTraits::NULL_TRAIT_VERSION, xorInstanceID(instanceIDValuePair.id)); + AvatarTraits::NULL_TRAIT_VERSION, + AvatarTraits::xoredInstanceID(instanceIDValuePair.id, + _owningAvatar->getTraitInstanceXORID())); } else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) { // pack delete for this trait instance AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id, - *traitsPacketList); + *traitsPacketList, AvatarTraits::NULL_TRAIT_VERSION, + AvatarTraits::xoredInstanceID(instanceIDValuePair.id, + _owningAvatar->getTraitInstanceXORID())); } } @@ -118,17 +122,6 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { } } -AvatarTraits::TraitInstanceID ClientTraitsHandler::xorInstanceID(AvatarTraits::TraitInstanceID localInstanceID) { - QByteArray xorInstanceID { NUM_BYTES_RFC4122_UUID, 0 }; - auto localInstanceIDBytes = localInstanceID.toRfc4122(); - - for (auto i = 0; i < localInstanceIDBytes.size(); ++i) { - xorInstanceID[i] = localInstanceIDBytes[i] ^ _sessionXORID[i]; - } - - return QUuid::fromRfc4122(xorInstanceID); -} - void ClientTraitsHandler::processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode) { if (sendingNode->getType() == NodeType::AvatarMixer) { while (message->getBytesLeftToRead()) { diff --git a/libraries/avatars/src/ClientTraitsHandler.h b/libraries/avatars/src/ClientTraitsHandler.h index 2319061502..6d1592ba74 100644 --- a/libraries/avatars/src/ClientTraitsHandler.h +++ b/libraries/avatars/src/ClientTraitsHandler.h @@ -37,8 +37,6 @@ public: void resetForNewMixer(); - AvatarTraits::TraitInstanceID xorInstanceID(AvatarTraits::TraitInstanceID localInstanceID); - public slots: void processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode); @@ -55,8 +53,6 @@ private: AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION }; AvatarTraits::TraitVersion _currentSkeletonVersion { AvatarTraits::NULL_TRAIT_VERSION }; - - QByteArray _sessionXORID { NUM_BYTES_RFC4122_UUID, 0}; bool _shouldPerformInitialSend { false }; bool _hasChangedTraits { false }; From a37a19da1e4e7657548fb29ad6cf4e130a5eda76 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Aug 2018 16:59:24 -0700 Subject: [PATCH 43/61] use different XORed instance ID for replicas --- libraries/avatars/src/AvatarHashMap.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index fac2af9ebc..c1246866dc 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -85,7 +85,8 @@ void AvatarReplicas::processDeletedTraitInstance(const QUuid& parentID, AvatarTr if (_replicasMap.find(parentID) != _replicasMap.end()) { auto &replicas = _replicasMap[parentID]; for (auto avatar : replicas) { - avatar->processDeletedTraitInstance(traitType, instanceID); + avatar->processDeletedTraitInstance(traitType, + AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID())); } } } @@ -94,7 +95,9 @@ void AvatarReplicas::processTraitInstance(const QUuid& parentID, AvatarTraits::T if (_replicasMap.find(parentID) != _replicasMap.end()) { auto &replicas = _replicasMap[parentID]; for (auto avatar : replicas) { - avatar->processTraitInstance(traitType, instanceID, traitBinaryData); + avatar->processTraitInstance(traitType, + AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()), + traitBinaryData); } } } @@ -353,11 +356,11 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess // in order to handle re-connections to the avatar mixer when the other if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) { avatar->processDeletedTraitInstance(traitType, xoredInstanceID); - _replicas.processDeletedTraitInstance(avatarID, traitType, xoredInstanceID); + _replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID); } else { auto traitData = message->read(traitBinarySize); avatar->processTraitInstance(traitType, xoredInstanceID, traitData); - _replicas.processTraitInstance(avatarID, traitType, xoredInstanceID, traitData); + _replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData); } processedInstanceVersion = packetTraitVersion; } else { From 96aa0549be8d21d05ea5b3826b5d9a869d50c225 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 1 Sep 2018 12:08:49 -0700 Subject: [PATCH 44/61] AVX2 implementation of crossfade_4x2() --- libraries/audio/src/AudioHRTF.cpp | 6 ++- libraries/audio/src/avx2/AudioHRTF_avx2.cpp | 57 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 655527a65c..eea01b703b 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -469,8 +469,12 @@ static void biquad2_4x4(float* src, float* dst, float coef[5][8], float state[3] (*f)(src, dst, coef, state, numFrames); // dispatch } +void crossfade_4x2_AVX2(float* src, float* dst, const float* win, int numFrames); + static void crossfade_4x2(float* src, float* dst, const float* win, int numFrames) { - crossfade_4x2_SSE(src, dst, win, numFrames); + + static auto f = cpuSupportsAVX2() ? crossfade_4x2_AVX2 : crossfade_4x2_SSE; + (*f)(src, dst, win, numFrames); // dispatch } static void interpolate(const float* src0, const float* src1, float* dst, float frac, float gain) { diff --git a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp index 9000df367f..b82098b72f 100644 --- a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp +++ b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp @@ -169,4 +169,61 @@ void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8 _mm256_zeroupper(); } +// crossfade 4 inputs into 2 outputs with accumulation (interleaved) +void crossfade_4x2_AVX2(float* src, float* dst, const float* win, int numFrames) { + + assert(numFrames % 8 == 0); + + for (int i = 0; i < numFrames; i += 8) { + + __m256 f0 = _mm256_loadu_ps(&win[i]); + + __m256 x0 = _mm256_castps128_ps256(_mm_loadu_ps(&src[4*i+0])); + __m256 x1 = _mm256_castps128_ps256(_mm_loadu_ps(&src[4*i+4])); + __m256 x2 = _mm256_castps128_ps256(_mm_loadu_ps(&src[4*i+8])); + __m256 x3 = _mm256_castps128_ps256(_mm_loadu_ps(&src[4*i+12])); + + x0 = _mm256_insertf128_ps(x0, _mm_loadu_ps(&src[4*i+16]), 1); + x1 = _mm256_insertf128_ps(x1, _mm_loadu_ps(&src[4*i+20]), 1); + x2 = _mm256_insertf128_ps(x2, _mm_loadu_ps(&src[4*i+24]), 1); + x3 = _mm256_insertf128_ps(x3, _mm_loadu_ps(&src[4*i+28]), 1); + + __m256 y0 = _mm256_loadu_ps(&dst[2*i+0]); + __m256 y1 = _mm256_loadu_ps(&dst[2*i+8]); + + // deinterleave (4x4 matrix transpose) + __m256 t0 = _mm256_unpacklo_ps(x0, x1); + __m256 t1 = _mm256_unpackhi_ps(x0, x1); + __m256 t2 = _mm256_unpacklo_ps(x2, x3); + __m256 t3 = _mm256_unpackhi_ps(x2, x3); + + x0 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(1,0,1,0)); + x1 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(3,2,3,2)); + x2 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(1,0,1,0)); + x3 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(3,2,3,2)); + + // crossfade + x0 = _mm256_sub_ps(x0, x2); + x1 = _mm256_sub_ps(x1, x3); + x2 = _mm256_fmadd_ps(f0, x0, x2); + x3 = _mm256_fmadd_ps(f0, x1, x3); + + // interleave + t0 = _mm256_unpacklo_ps(x2, x3); + t1 = _mm256_unpackhi_ps(x2, x3); + + x0 = _mm256_permute2f128_ps(t0, t1, 0x20); + x1 = _mm256_permute2f128_ps(t0, t1, 0x31); + + // accumulate + y0 = _mm256_add_ps(y0, x0); + y1 = _mm256_add_ps(y1, x1); + + _mm256_storeu_ps(&dst[2*i+0], y0); + _mm256_storeu_ps(&dst[2*i+8], y1); + } + + _mm256_zeroupper(); +} + #endif From 06af7b8729595d90ee8dec8dd86d74e7130763a6 Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 07:58:39 -0400 Subject: [PATCH 45/61] Fixed typo on DQT_CMAKE_PREFIX_PATH --- BUILD_LINUX.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 0daef5ae05..55e7260cd1 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -66,7 +66,7 @@ cd hifi/build Prepare makefiles: ```bash -cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10/gcc_64/lib/cmake .. +cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake .. ``` Start compilation and get a cup of coffee: From 229a3bba90e0ed9279e0064067f5353860cfbe2e Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:00:16 -0400 Subject: [PATCH 46/61] Added zlib1g-dev to required dependencies --- BUILD_LINUX.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 55e7260cd1..48e5a8efc1 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -6,7 +6,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required: - libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev + libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev ## Ubuntu 16.04 specific build guide @@ -20,7 +20,7 @@ sudo dpkg -i hifiqt5.10.1_5.10.1_amd64.deb Install build dependencies: ```bash -sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev +sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev ``` To compile interface in a server you must install: From f509dc4af4f9ef5c95640cb7bc680c2071166efb Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:11:15 -0400 Subject: [PATCH 47/61] Added Ubuntu 18.04 step to add universe repository --- BUILD_LINUX.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 48e5a8efc1..421e81c8b8 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -8,7 +8,14 @@ Should you choose not to install Qt5 via a package manager that handles dependen libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev -## Ubuntu 16.04 specific build guide +## Ubuntu 16.04/18.04 specific build guide + +### Ubuntu 18.04 only +Add the universe repository (not enabled by default on the server edition): +```bash +sudo add-apt-repository universe +sudo apt-get update +``` ### Prepare environment hifiqt5.10.1 @@ -33,6 +40,7 @@ Install build tools: sudo apt install cmake ``` + ### Get code and checkout the tag you need Clone this repository: From 03051c0916b48814c92664647b69c2b383e66ab1 Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:16:50 -0400 Subject: [PATCH 48/61] Revised Qt statement and Improved 18.04 step format --- BUILD_LINUX.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 421e81c8b8..c7351d4834 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -11,15 +11,15 @@ Should you choose not to install Qt5 via a package manager that handles dependen ## Ubuntu 16.04/18.04 specific build guide ### Ubuntu 18.04 only -Add the universe repository (not enabled by default on the server edition): +Add the universe repository: +_(This is not enabled by default on the server edition)_ ```bash sudo add-apt-repository universe sudo apt-get update ``` ### Prepare environment -hifiqt5.10.1 -Install qt: +Install Qt 5.10.1: ```bash wget http://debian.highfidelity.com/pool/h/hi/hifiqt5.10.1_5.10.1_amd64.deb sudo dpkg -i hifiqt5.10.1_5.10.1_amd64.deb From b0fe721af19902cccb5a22c533d57f57b497e7fb Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:22:58 -0400 Subject: [PATCH 49/61] Revised checkout tag and removed download page mention --- BUILD_LINUX.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index c7351d4834..8b1f77e538 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -56,12 +56,7 @@ git tags Then checkout last tag with: ```bash -git checkout tags/RELEASE-6819 -``` - -Or go to the highfidelity download page (https://highfidelity.com/download) to get the release version. For example, if there is a BETA 6731 type: -```bash -git checkout tags/RELEASE-6731 +git checkout tags/v0.71.0 ``` ### Compiling From 143b4a61dd2821699249ffd8faca60abd88a00a5 Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:25:45 -0400 Subject: [PATCH 50/61] Revised server compilation statement and grammer error --- BUILD_LINUX.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 8b1f77e538..e95ee2f4d4 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -72,12 +72,17 @@ Prepare makefiles: cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake .. ``` -Start compilation and get a cup of coffee: +Start compilation of the server and get a cup of coffee: ```bash -make domain-server assignment-client interface +make domain-server assignment-client ``` -In a server does not make sense to compile interface +To compile interferace: +```bash +make interface +``` + +In a server, it does not make sense to compile interface ### Running the software From 26cb2409b95bafe86e5766b61ca9729bdebcef0d Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:53:20 -0400 Subject: [PATCH 51/61] Added additional export QT_CMAKE_PREFIX_PATH related to BUILD_LINUX.md --- BUILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD.md b/BUILD.md index 4a0274cea6..df3f18cf51 100644 --- a/BUILD.md +++ b/BUILD.md @@ -46,6 +46,7 @@ This can either be entered directly into your shell session before you build or The path it needs to be set to will depend on where and how Qt5 was installed. e.g. + export QT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.10.1/clang_64/lib/cmake/ export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.10.1/lib/cmake export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake From 8314386426cf494d6cfe6d0ebd378adc8bde0e84 Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 08:55:15 -0400 Subject: [PATCH 52/61] Revised all apt statements to apt-get for consistency --- BUILD_LINUX.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index e95ee2f4d4..019b19ff8c 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -32,12 +32,12 @@ sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-de To compile interface in a server you must install: ```bash -sudo apt -y install libpulse0 libnss3 libnspr4 libfontconfig1 libxcursor1 libxcomposite1 libxtst6 libxslt1.1 +sudo apt-get -y install libpulse0 libnss3 libnspr4 libfontconfig1 libxcursor1 libxcomposite1 libxtst6 libxslt1.1 ``` Install build tools: ```bash -sudo apt install cmake +sudo apt-get install cmake ``` @@ -101,4 +101,4 @@ Running interface: ./interface/interface ``` -Go to localhost in running interface. +Go to localhost in the running interface. From 94e8ee99f5cade6f6f9a9bcf179c6b229a05cc37 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 3 Sep 2018 13:06:49 -0700 Subject: [PATCH 53/61] AVX2 implementation of interpolate() --- libraries/audio/src/AudioHRTF.cpp | 6 +++++- libraries/audio/src/avx2/AudioHRTF_avx2.cpp | 22 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index eea01b703b..b52f624620 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -477,8 +477,12 @@ static void crossfade_4x2(float* src, float* dst, const float* win, int numFrame (*f)(src, dst, win, numFrames); // dispatch } +void interpolate_AVX2(const float* src0, const float* src1, float* dst, float frac, float gain); + static void interpolate(const float* src0, const float* src1, float* dst, float frac, float gain) { - interpolate_SSE(src0, src1, dst, frac, gain); + + static auto f = cpuSupportsAVX2() ? interpolate_AVX2 : interpolate_SSE; + (*f)(src0, src1, dst, frac, gain); // dispatch } #else // portable reference code diff --git a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp index b82098b72f..aadbb2d0cd 100644 --- a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp +++ b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp @@ -226,4 +226,26 @@ void crossfade_4x2_AVX2(float* src, float* dst, const float* win, int numFrames) _mm256_zeroupper(); } +// linear interpolation with gain +void interpolate_AVX2(const float* src0, const float* src1, float* dst, float frac, float gain) { + + __m256 f0 = _mm256_set1_ps(gain * (1.0f - frac)); + __m256 f1 = _mm256_set1_ps(gain * frac); + + static_assert(HRTF_TAPS % 8 == 0, "HRTF_TAPS must be a multiple of 8"); + + for (int k = 0; k < HRTF_TAPS; k += 8) { + + __m256 x0 = _mm256_loadu_ps(&src0[k]); + __m256 x1 = _mm256_loadu_ps(&src1[k]); + + x0 = _mm256_mul_ps(f0, x0); + x0 = _mm256_fmadd_ps(f1, x1, x0); + + _mm256_storeu_ps(&dst[k], x0); + } + + _mm256_zeroupper(); +} + #endif From f5b7232f58906e82e24c22b12e778746f946b033 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 3 Sep 2018 14:00:30 -0700 Subject: [PATCH 54/61] Cleanup --- libraries/audio/src/AudioHRTF.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index b52f624620..b639301404 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -446,41 +446,32 @@ static void interpolate_SSE(const float* src0, const float* src1, float* dst, fl void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); +void interleave_4x4_AVX2(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames); +void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames); +void crossfade_4x2_AVX2(float* src, float* dst, const float* win, int numFrames); +void interpolate_AVX2(const float* src0, const float* src1, float* dst, float frac, float gain); static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { - static auto f = cpuSupportsAVX512() ? FIR_1x4_AVX512 : (cpuSupportsAVX2() ? FIR_1x4_AVX2 : FIR_1x4_SSE); (*f)(src, dst0, dst1, dst2, dst3, coef, numFrames); // dispatch } -void interleave_4x4_AVX2(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames); - static void interleave_4x4(float* src0, float* src1, float* src2, float* src3, float* dst, int numFrames) { - static auto f = cpuSupportsAVX2() ? interleave_4x4_AVX2 : interleave_4x4_SSE; (*f)(src0, src1, src2, src3, dst, numFrames); // dispatch } -void biquad2_4x4_AVX2(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames); - static void biquad2_4x4(float* src, float* dst, float coef[5][8], float state[3][8], int numFrames) { - static auto f = cpuSupportsAVX2() ? biquad2_4x4_AVX2 : biquad2_4x4_SSE; (*f)(src, dst, coef, state, numFrames); // dispatch } -void crossfade_4x2_AVX2(float* src, float* dst, const float* win, int numFrames); - static void crossfade_4x2(float* src, float* dst, const float* win, int numFrames) { - static auto f = cpuSupportsAVX2() ? crossfade_4x2_AVX2 : crossfade_4x2_SSE; (*f)(src, dst, win, numFrames); // dispatch } -void interpolate_AVX2(const float* src0, const float* src1, float* dst, float frac, float gain); - static void interpolate(const float* src0, const float* src1, float* dst, float frac, float gain) { - static auto f = cpuSupportsAVX2() ? interpolate_AVX2 : interpolate_SSE; (*f)(src0, src1, dst, frac, gain); // dispatch } From b5f1c82e61ca6994736dd7f3f04a089f6c241d1b Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Mon, 3 Sep 2018 18:21:04 -0400 Subject: [PATCH 55/61] Corrected interferace to interface --- BUILD_LINUX.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 019b19ff8c..1ee3d2b7c8 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -77,7 +77,7 @@ Start compilation of the server and get a cup of coffee: make domain-server assignment-client ``` -To compile interferace: +To compile interface: ```bash make interface ``` From 24cf4adb44a55d79fe3a97f1a72dc4c2b238032f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 4 Sep 2018 09:08:42 -0700 Subject: [PATCH 56/61] Fix MS17902: Prevent case where My Purchases says Open instead of Uninstall --- interface/src/commerce/QmlCommerce.cpp | 59 +++++++++++++++----------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 1c6600cf3f..06da18148f 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -40,11 +40,9 @@ QmlCommerce::QmlCommerce() { connect(ledger.data(), &Ledger::transferAssetToUsernameResult, this, &QmlCommerce::transferAssetToUsernameResult); connect(ledger.data(), &Ledger::availableUpdatesResult, this, &QmlCommerce::availableUpdatesResult); connect(ledger.data(), &Ledger::updateItemResult, this, &QmlCommerce::updateItemResult); - + auto accountManager = DependencyManager::get(); - connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { - setPassphrase(""); - }); + connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { setPassphrase(""); }); _appsPath = PathUtils::getAppDataPath() + "Apps/"; } @@ -105,7 +103,11 @@ void QmlCommerce::balance() { } } -void QmlCommerce::inventory(const QString& editionFilter, const QString& typeFilter, const QString& titleFilter, const int& page, const int& perPage) { +void QmlCommerce::inventory(const QString& editionFilter, + const QString& typeFilter, + const QString& titleFilter, + const int& page, + const int& perPage) { auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); QStringList cachedPublicKeys = wallet->listPublicKeys(); @@ -166,24 +168,30 @@ void QmlCommerce::certificateInfo(const QString& certificateId) { ledger->certificateInfo(certificateId); } -void QmlCommerce::transferAssetToNode(const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage) { +void QmlCommerce::transferAssetToNode(const QString& nodeID, + const QString& certificateID, + const int& amount, + const QString& optionalMessage) { auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); QStringList keys = wallet->listPublicKeys(); if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } }; + QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; return emit transferAssetToNodeResult(result); } QString key = keys[0]; ledger->transferAssetToNode(key, nodeID, certificateID, amount, optionalMessage); } -void QmlCommerce::transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage) { +void QmlCommerce::transferAssetToUsername(const QString& username, + const QString& certificateID, + const int& amount, + const QString& optionalMessage) { auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); QStringList keys = wallet->listPublicKeys(); if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } }; + QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; return emit transferAssetToUsernameResult(result); } QString key = keys[0]; @@ -194,10 +202,7 @@ void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& cert auto ledger = DependencyManager::get(); ledger->updateLocation(certificateID, DependencyManager::get()->getPlaceName(), true); qApp->replaceDomainContent(itemHref); - QJsonObject messageProperties = { - { "status", "SuccessfulRequestToReplaceContent" }, - { "content_set_url", itemHref } - }; + QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, { "content_set_url", itemHref } }; UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); emit contentSetChanged(itemHref); @@ -214,10 +219,7 @@ QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) { QDir directory(_appsPath); QStringList apps = directory.entryList(QStringList("*.app.json")); - foreach(QString appFileName, apps) { - installedAppsFromMarketplace += appFileName; - installedAppsFromMarketplace += ","; - + foreach (QString appFileName, apps) { // If we were supplied a "justInstalledAppID" argument, that means we're entering this function // to get the new list of installed apps immediately after installing an app. // In that case, the app we installed may not yet have its associated script running - @@ -243,10 +245,12 @@ QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) { // delete the .app.json from the user's local disk. if (!runningScripts.contains(scriptURL)) { if (!appFile.remove()) { - qCWarning(commerce) - << "Couldn't delete local .app.json file (app's script isn't running). App filename is:" - << appFileName; + qCWarning(commerce) << "Couldn't delete local .app.json file (app's script isn't running). App filename is:" + << appFileName; } + } else { + installedAppsFromMarketplace += appFileName; + installedAppsFromMarketplace += ","; } } else { qCDebug(commerce) << "Couldn't open local .app.json file for reading."; @@ -317,7 +321,9 @@ bool QmlCommerce::uninstallApp(const QString& itemHref) { // Read from the file to know what .js script to stop QFile appFile(_appsPath + "/" + appHref.fileName()); if (!appFile.open(QIODevice::ReadOnly)) { - qCDebug(commerce) << "Couldn't open local .app.json file for deletion. Cannot continue with app uninstallation. App filename is:" << appHref.fileName(); + qCDebug(commerce) + << "Couldn't open local .app.json file for deletion. Cannot continue with app uninstallation. App filename is:" + << appHref.fileName(); return false; } QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); @@ -325,13 +331,15 @@ bool QmlCommerce::uninstallApp(const QString& itemHref) { QString scriptUrl = appFileJsonObject["scriptURL"].toString(); if (!DependencyManager::get()->stopScript(scriptUrl.trimmed(), false)) { - qCWarning(commerce) << "Couldn't stop script during app uninstall. Continuing anyway. ScriptURL is:" << scriptUrl.trimmed(); + qCWarning(commerce) << "Couldn't stop script during app uninstall. Continuing anyway. ScriptURL is:" + << scriptUrl.trimmed(); } // Delete the .app.json from the filesystem // remove() closes the file first. if (!appFile.remove()) { - qCWarning(commerce) << "Couldn't delete local .app.json file during app uninstall. Continuing anyway. App filename is:" << appHref.fileName(); + qCWarning(commerce) << "Couldn't delete local .app.json file during app uninstall. Continuing anyway. App filename is:" + << appHref.fileName(); } QFileInfo appFileInfo(appFile); @@ -352,7 +360,8 @@ bool QmlCommerce::openApp(const QString& itemHref) { QJsonObject appFileJsonObject = appFileJsonDocument.object(); QString homeUrl = appFileJsonObject["homeURL"].toString(); - auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); + auto tablet = dynamic_cast( + DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); if (homeUrl.contains(".qml", Qt::CaseInsensitive)) { tablet->loadQMLSource(homeUrl); } else if (homeUrl.contains(".html", Qt::CaseInsensitive)) { @@ -377,7 +386,7 @@ void QmlCommerce::updateItem(const QString& certificateId) { auto wallet = DependencyManager::get(); QStringList keys = wallet->listPublicKeys(); if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } }; + QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; return emit updateItemResult(result); } QString key = keys[0]; From 3a034fdf66a4311d1e7231cdde608f2fef69d8f2 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 31 Aug 2018 13:14:15 -0700 Subject: [PATCH 57/61] HMD mode bug fix for avatars with no eyes Previously getCenterEyeCalibrationMat() would return the average eye position for an avatar, if the eyes are missing. Now we fall back to using the HeadCalibrationMat() and adding an offset from the head to the center of the eyes. This is more accurate for characters that don't quite have human proportions. --- interface/src/avatar/MyAvatar.cpp | 4 +++- libraries/shared/src/AvatarConstants.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 640c9821a0..930a1b9f81 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4313,7 +4313,8 @@ glm::mat4 MyAvatar::getCenterEyeCalibrationMat() const { auto centerEyeRot = Quaternions::Y_180; return createMatFromQuatAndPos(centerEyeRot, centerEyePos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, DEFAULT_AVATAR_MIDDLE_EYE_POS / getSensorToWorldScale()); + glm::mat4 headMat = getHeadCalibrationMat(); + return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, extractTranslation(headMat) + (DEFAULT_AVATAR_HEAD_TO_MIDDLE_EYE_OFFSET / getSensorToWorldScale())); } } @@ -4323,6 +4324,7 @@ glm::mat4 MyAvatar::getHeadCalibrationMat() const { if (headIndex >= 0) { auto headPos = getAbsoluteDefaultJointTranslationInObjectFrame(headIndex); auto headRot = getAbsoluteDefaultJointRotationInObjectFrame(headIndex); + return createMatFromQuatAndPos(headRot, headPos / getSensorToWorldScale()); } else { return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_ROT, DEFAULT_AVATAR_HEAD_POS / getSensorToWorldScale()); diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index c3e8a3f173..986d39e94d 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -44,7 +44,7 @@ const float DEFAULT_AVATAR_RIGHTHAND_MASS = 2.0f; // Used when avatar is missing joints... (avatar space) const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 }; -const glm::vec3 DEFAULT_AVATAR_MIDDLE_EYE_POS { 0.0f, 0.6f, 0.0f }; +const glm::vec3 DEFAULT_AVATAR_HEAD_TO_MIDDLE_EYE_OFFSET = { 0.0f, 0.06f, -0.09f }; const glm::vec3 DEFAULT_AVATAR_HEAD_POS { 0.0f, 0.53f, 0.0f }; const glm::quat DEFAULT_AVATAR_HEAD_ROT { Quaternions::Y_180 }; const glm::vec3 DEFAULT_AVATAR_RIGHTARM_POS { -0.134824f, 0.396348f, -0.0515777f }; From ade58a52cc97fe06c2f4bb88c4b9d097636fd4b9 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 4 Sep 2018 10:33:01 -0700 Subject: [PATCH 58/61] reserve priority sort util vectors --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 1 + interface/src/avatar/AvatarManager.cpp | 5 +++-- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 1 + libraries/shared/src/PrioritySortUtil.h | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 59c6db5dc4..c434d82116 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -329,6 +329,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, AvatarData::_avatarSortCoefficientAge); + sortedAvatars.reserve(avatarsToSort.size()); // ignore or sort const AvatarSharedPointer& thisAvatar = nodeData->getAvatarSharedPointer(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bd98549510..e9486b9def 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -187,16 +187,17 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { AvatarSharedPointer _avatar; }; + auto avatarMap = getHashCopy(); + AvatarHash::iterator itr = avatarMap.begin(); const auto& views = qApp->getConicalViews(); PrioritySortUtil::PriorityQueue sortedAvatars(views, AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, AvatarData::_avatarSortCoefficientAge); + sortedAvatars.reserve(avatarMap.size() - 1); // don't include MyAvatar // sort - auto avatarMap = getHashCopy(); - AvatarHash::iterator itr = avatarMap.begin(); while (itr != avatarMap.end()) { const auto& avatar = std::static_pointer_cast(*itr); // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a363093083..3d782f69a7 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -382,6 +382,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene const auto& views = _viewState->getConicalViews(); PrioritySortUtil::PriorityQueue sortedRenderables(views); + sortedRenderables.reserve(_renderablesToUpdate.size()); { PROFILE_RANGE_EX(simulation_physics, "SortRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size()); std::unordered_map::iterator itr = _renderablesToUpdate.begin(); diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index e0137b3d8c..8ded047212 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -100,6 +100,9 @@ namespace PrioritySortUtil { thing.setPriority(computePriority(thing)); _vector.push_back(thing); } + void reserve(size_t num) { + _vector.reserve(num); + } const std::vector& getSortedVector() { std::sort(_vector.begin(), _vector.end(), [](const T& left, const T& right) { return left.getPriority() > right.getPriority(); }); return _vector; From b21fa1037f1ff54fcec00af5026238a8c19a4b20 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Tue, 4 Sep 2018 11:55:52 -0700 Subject: [PATCH 59/61] Code review feedback and bug fixes for calibraiton matrices --- interface/src/avatar/MyAvatar.cpp | 21 +++++++++---------- interface/src/avatar/MyAvatar.h | 2 +- libraries/controllers/src/controllers/Input.h | 20 +++++++++--------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 930a1b9f81..e4503b4e78 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4314,7 +4314,7 @@ glm::mat4 MyAvatar::getCenterEyeCalibrationMat() const { return createMatFromQuatAndPos(centerEyeRot, centerEyePos / getSensorToWorldScale()); } else { glm::mat4 headMat = getHeadCalibrationMat(); - return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, extractTranslation(headMat) + (DEFAULT_AVATAR_HEAD_TO_MIDDLE_EYE_OFFSET / getSensorToWorldScale())); + return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, extractTranslation(headMat) + DEFAULT_AVATAR_HEAD_TO_MIDDLE_EYE_OFFSET); } } @@ -4327,7 +4327,7 @@ glm::mat4 MyAvatar::getHeadCalibrationMat() const { return createMatFromQuatAndPos(headRot, headPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_ROT, DEFAULT_AVATAR_HEAD_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_ROT, DEFAULT_AVATAR_HEAD_POS); } } @@ -4339,7 +4339,7 @@ glm::mat4 MyAvatar::getSpine2CalibrationMat() const { auto spine2Rot = getAbsoluteDefaultJointRotationInObjectFrame(spine2Index); return createMatFromQuatAndPos(spine2Rot, spine2Pos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_SPINE2_ROT, DEFAULT_AVATAR_SPINE2_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_SPINE2_ROT, DEFAULT_AVATAR_SPINE2_POS); } } @@ -4351,7 +4351,7 @@ glm::mat4 MyAvatar::getHipsCalibrationMat() const { auto hipsRot = getAbsoluteDefaultJointRotationInObjectFrame(hipsIndex); return createMatFromQuatAndPos(hipsRot, hipsPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_HIPS_ROT, DEFAULT_AVATAR_HIPS_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_HIPS_ROT, DEFAULT_AVATAR_HIPS_POS); } } @@ -4363,7 +4363,7 @@ glm::mat4 MyAvatar::getLeftFootCalibrationMat() const { auto leftFootRot = getAbsoluteDefaultJointRotationInObjectFrame(leftFootIndex); return createMatFromQuatAndPos(leftFootRot, leftFootPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTFOOT_ROT, DEFAULT_AVATAR_LEFTFOOT_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTFOOT_ROT, DEFAULT_AVATAR_LEFTFOOT_POS); } } @@ -4375,11 +4375,10 @@ glm::mat4 MyAvatar::getRightFootCalibrationMat() const { auto rightFootRot = getAbsoluteDefaultJointRotationInObjectFrame(rightFootIndex); return createMatFromQuatAndPos(rightFootRot, rightFootPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTFOOT_ROT, DEFAULT_AVATAR_RIGHTFOOT_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTFOOT_ROT, DEFAULT_AVATAR_RIGHTFOOT_POS); } } - glm::mat4 MyAvatar::getRightArmCalibrationMat() const { int rightArmIndex = _skeletonModel->getRig().indexOfJoint("RightArm"); if (rightArmIndex >= 0) { @@ -4387,7 +4386,7 @@ glm::mat4 MyAvatar::getRightArmCalibrationMat() const { auto rightArmRot = getAbsoluteDefaultJointRotationInObjectFrame(rightArmIndex); return createMatFromQuatAndPos(rightArmRot, rightArmPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTARM_ROT, DEFAULT_AVATAR_RIGHTARM_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTARM_ROT, DEFAULT_AVATAR_RIGHTARM_POS); } } @@ -4398,7 +4397,7 @@ glm::mat4 MyAvatar::getLeftArmCalibrationMat() const { auto leftArmRot = getAbsoluteDefaultJointRotationInObjectFrame(leftArmIndex); return createMatFromQuatAndPos(leftArmRot, leftArmPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTARM_ROT, DEFAULT_AVATAR_LEFTARM_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTARM_ROT, DEFAULT_AVATAR_LEFTARM_POS); } } @@ -4409,7 +4408,7 @@ glm::mat4 MyAvatar::getRightHandCalibrationMat() const { auto rightHandRot = getAbsoluteDefaultJointRotationInObjectFrame(rightHandIndex); return createMatFromQuatAndPos(rightHandRot, rightHandPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTHAND_ROT, DEFAULT_AVATAR_RIGHTHAND_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTHAND_ROT, DEFAULT_AVATAR_RIGHTHAND_POS); } } @@ -4420,7 +4419,7 @@ glm::mat4 MyAvatar::getLeftHandCalibrationMat() const { auto leftHandRot = getAbsoluteDefaultJointRotationInObjectFrame(leftHandIndex); return createMatFromQuatAndPos(leftHandRot, leftHandPos / getSensorToWorldScale()); } else { - return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTHAND_ROT, DEFAULT_AVATAR_LEFTHAND_POS / getSensorToWorldScale()); + return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTHAND_ROT, DEFAULT_AVATAR_LEFTHAND_POS); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8121b99e55..06267b3819 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1034,7 +1034,7 @@ public: virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override; virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; - // all calibration matrices are in absolute avatar space. + // all calibration matrices are in absolute sensor space. glm::mat4 getCenterEyeCalibrationMat() const; glm::mat4 getHeadCalibrationMat() const; glm::mat4 getSpine2CalibrationMat() const; diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h index 3ca4076de2..3c01ee0942 100644 --- a/libraries/controllers/src/controllers/Input.h +++ b/libraries/controllers/src/controllers/Input.h @@ -19,16 +19,16 @@ struct InputCalibrationData { glm::mat4 sensorToWorldMat; // sensor to world glm::mat4 avatarMat; // avatar to world glm::mat4 hmdSensorMat; // hmd pos and orientation in sensor space - glm::mat4 defaultCenterEyeMat; // default pose for the center of the eyes in avatar space. - glm::mat4 defaultHeadMat; // default pose for head joint in avatar space - glm::mat4 defaultSpine2; // default pose for spine2 joint in avatar space - glm::mat4 defaultHips; // default pose for hips joint in avatar space - glm::mat4 defaultLeftFoot; // default pose for leftFoot joint in avatar space - glm::mat4 defaultRightFoot; // default pose for rightFoot joint in avatar space - glm::mat4 defaultRightArm; // default pose for rightArm joint in avatar space - glm::mat4 defaultLeftArm; // default pose for leftArm joint in avatar space - glm::mat4 defaultRightHand; // default pose for rightHand joint in avatar space - glm::mat4 defaultLeftHand; // default pose for leftHand joint in avatar space + glm::mat4 defaultCenterEyeMat; // default pose for the center of the eyes in sensor space. + glm::mat4 defaultHeadMat; // default pose for head joint in sensor space + glm::mat4 defaultSpine2; // default pose for spine2 joint in sensor space + glm::mat4 defaultHips; // default pose for hips joint in sensor space + glm::mat4 defaultLeftFoot; // default pose for leftFoot joint in sensor space + glm::mat4 defaultRightFoot; // default pose for rightFoot joint in sensor space + glm::mat4 defaultRightArm; // default pose for rightArm joint in sensor space + glm::mat4 defaultLeftArm; // default pose for leftArm joint in sensor space + glm::mat4 defaultRightHand; // default pose for rightHand joint in sensor space + glm::mat4 defaultLeftHand; // default pose for leftHand joint in sensor space }; enum class ChannelType { From e210fadc7cb599b9f6a72b5dade5398678ca51f7 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Tue, 4 Sep 2018 14:36:56 -0700 Subject: [PATCH 60/61] Fix for glitch when entering inAir state from takeoff. This was due to a frame lag of blend factor used for inAir blending. So the first frame the upward velocity would be 0, followed by 3.5 m/s the next frame. This is fixed by using the workingVelocity instead of _lastVelocity to drive the blend. --- libraries/animation/src/Rig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index c3e679096b..13cf165dac 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -926,7 +926,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos // compute blend based on velocity const float JUMP_SPEED = 3.5f; - float alpha = glm::clamp(-_lastVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f; + float alpha = glm::clamp(-workingVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f; _animVars.set("inAirAlpha", alpha); } From 9e76c164ac76fcc6dfadb05b79da96a862188d97 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 4 Sep 2018 16:25:47 -0700 Subject: [PATCH 61/61] fix aabox operator+= --- libraries/shared/src/AABox.h | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index e0bb1343f8..f41bb8a814 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -86,19 +86,12 @@ public: AABox clamp(float min, float max) const; inline AABox& operator+=(const glm::vec3& point) { - // Branchless version of: - //if (isInvalid()) { - // _corner = glm::min(_corner, point); - //} else { - // glm::vec3 maximum(_corner + _scale); - // _corner = glm::min(_corner, point); - // maximum = glm::max(maximum, point); - // _scale = maximum - _corner; - //} - float blend = (float)isInvalid(); - glm::vec3 maximumScale(glm::max(_scale, point - _corner)); + bool valid = !isInvalid(); + glm::vec3 maximum = glm::max(_corner + _scale, point); _corner = glm::min(_corner, point); - _scale = blend * _scale + (1.0f - blend) * maximumScale; + if (valid) { + _scale = maximum - _corner; + } return (*this); } @@ -136,7 +129,7 @@ public: static const glm::vec3 INFINITY_VECTOR; - bool isInvalid() const { return _corner == INFINITY_VECTOR; } + bool isInvalid() const { return _corner.x == std::numeric_limits::infinity(); } void clear() { _corner = INFINITY_VECTOR; _scale = glm::vec3(0.0f); }