diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index cf3f380ca0..d3991eac24 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -12,7 +12,7 @@ #include "avatar/AvatarManager.h" -JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) : +JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), _posOffset(posOffset), @@ -20,7 +20,7 @@ JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOff { } -const PickRay JointRayPick::getPickRay(bool& valid) const { +const PickRay JointRayPick::getMathematicalPick(bool& valid) const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName)); bool useAvatarHead = _jointName == "Avatar"; diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index e3e5670e20..b2bffe83c4 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -11,14 +11,14 @@ #ifndef hifi_JointRayPick_h #define hifi_JointRayPick_h -#include +#include "RayPick.h" class JointRayPick : public RayPick { public: - JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) const override; + const PickRay getMathematicalPick(bool& valid) const override; private: std::string _jointName; diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp index de59fde88d..27080f5857 100644 --- a/interface/src/raypick/MouseRayPick.cpp +++ b/interface/src/raypick/MouseRayPick.cpp @@ -10,16 +10,15 @@ // #include "MouseRayPick.h" -#include "DependencyManager.h" #include "Application.h" #include "display-plugins/CompositorHelper.h" -MouseRayPick::MouseRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) : +MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled) { } -const PickRay MouseRayPick::getPickRay(bool& valid) const { +const PickRay MouseRayPick::getMathematicalPick(bool& valid) const { QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition(); if (position.isValid()) { QVariantMap posMap = position.toMap(); diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index 47f9404f3a..c565a03db7 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -11,14 +11,14 @@ #ifndef hifi_MouseRayPick_h #define hifi_MouseRayPick_h -#include +#include "RayPick.h" class MouseRayPick : public RayPick { public: - MouseRayPick(const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) const override; + const PickRay getMathematicalPick(bool& valid) const override; }; #endif // hifi_MouseRayPick_h diff --git a/interface/src/raypick/Pick.cpp b/interface/src/raypick/Pick.cpp new file mode 100644 index 0000000000..030d2ef4b7 --- /dev/null +++ b/interface/src/raypick/Pick.cpp @@ -0,0 +1,10 @@ +// +// Created by Sam Gondelman 10/17/2017 +// Copyright 2017 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 "Pick.h" + +const PickFilter PickFilter::NOTHING; \ No newline at end of file diff --git a/libraries/pointers/src/pointers/rays/RayPick.h b/interface/src/raypick/Pick.h similarity index 51% rename from libraries/pointers/src/pointers/rays/RayPick.h rename to interface/src/raypick/Pick.h index 5a53891dc6..561c336f3b 100644 --- a/libraries/pointers/src/pointers/rays/RayPick.h +++ b/interface/src/raypick/Pick.h @@ -1,12 +1,12 @@ // -// Created by Sam Gondelman 7/11/2017 +// Created by Sam Gondelman 10/17/2017 // Copyright 2017 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_RayPick_h -#define hifi_RayPick_h +#ifndef hifi_Pick_h +#define hifi_Pick_h #include #include @@ -16,7 +16,10 @@ #include #include -class RayPickFilter { +#include "EntityScriptingInterface.h" +#include "ui/overlays/Overlays.h" + +class PickFilter { public: enum FlagBit { PICK_ENTITIES = 0, @@ -39,11 +42,11 @@ public: // The key is the Flags Flags _flags; - RayPickFilter() {} - RayPickFilter(const Flags& flags) : _flags(flags) {} + PickFilter() {} + PickFilter(const Flags& flags) : _flags(flags) {} - bool operator== (const RayPickFilter& rhs) const { return _flags == rhs._flags; } - bool operator!= (const RayPickFilter& rhs) const { return _flags != rhs._flags; } + bool operator== (const PickFilter& rhs) const { return _flags == rhs._flags; } + bool operator!= (const PickFilter& rhs) const { return _flags != rhs._flags; } void setFlag(FlagBit flag, bool value) { _flags[flag] = value; } @@ -91,29 +94,42 @@ public: static constexpr unsigned int getBitMask(FlagBit bit) { return 1 << bit; } - static const RayPickFilter NOTHING; + static const PickFilter NOTHING; }; -class RayPick : protected ReadWriteLockable { +template +class Pick : protected ReadWriteLockable { public: - using Pointer = std::shared_ptr; + using Pointer = std::shared_ptr>; - RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled); + Pick(const PickFilter& filter, const float maxDistance, const bool enabled); - virtual const PickRay getPickRay(bool& valid) const = 0; + virtual const T getMathematicalPick(bool& valid) const = 0; + virtual RayToEntityIntersectionResult getEntityIntersection(const T& pick, bool precisionPicking, + const QVector& entitiesToInclude, + const QVector& entitiesToIgnore, + bool visibleOnly, bool collidableOnly) = 0; + virtual RayToOverlayIntersectionResult getOverlayIntersection(const T& pick, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToIgnore, + bool visibleOnly, bool collidableOnly) = 0; + virtual RayToAvatarIntersectionResult getAvatarIntersection(const T& pick, + const QVector& avatarsToInclude, + const QVector& avatarsToIgnore) = 0; + virtual glm::vec3 getHUDIntersection(const T& pick) = 0; void enable(bool enabled = true); void disable() { enable(false); } - RayPickFilter getFilter() const; + PickFilter getFilter() const; float getMaxDistance() const; bool isEnabled() const; - RayPickResult getPrevRayPickResult() const; + RayPickResult getPrevPickResult() const; void setPrecisionPicking(bool precisionPicking); - void setRayPickResult(const RayPickResult& rayPickResult); + void setPickResult(const RayPickResult& rayPickResult); QVector getIgnoreItems() const; QVector getIncludeItems() const; @@ -144,7 +160,7 @@ public: void setIncludeItems(const QVector& items); private: - RayPickFilter _filter; + PickFilter _filter; const float _maxDistance; bool _enabled; RayPickResult _prevResult; @@ -153,4 +169,87 @@ private: QVector _includeItems; }; -#endif // hifi_RayPick_h + +template +Pick::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : + _filter(filter), + _maxDistance(maxDistance), + _enabled(enabled) { +} + +template +void Pick::enable(bool enabled) { + withWriteLock([&] { + _enabled = enabled; + }); +} + +template +PickFilter Pick::getFilter() const { + return resultWithReadLock([&] { + return _filter; + }); +} + +template +float Pick::getMaxDistance() const { + return _maxDistance; +} + +template +bool Pick::isEnabled() const { + withReadLock([&]) { + return _enabled; + } +} + +template +void Pick::setPrecisionPicking(bool precisionPicking) { + withWriteLock([&] { + _filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking); + }); +} + +template +void Pick::setPickResult(const RayPickResult& PickResult) { + withWriteLock([&] { + _prevResult = PickResult; + }); +} + +template +QVector Pick::getIgnoreItems() const { + withReadLock([&]) { + return _ignoreItems; + } +} + +template +QVector Pick::getIncludeItems() const { + withReadLock([&]) { + return _includeItems; + } +} + +template +RayPickResult Pick::getPrevPickResult() const { + return resultWithReadLock([&] { + return _prevResult; + }); +} + +template +void Pick::setIgnoreItems(const QVector& ignoreItems) { + withWriteLock([&] { + _ignoreItems = ignoreItems; + }); +} + +template +void Pick::setIncludeItems(const QVector& includeItems) { + withWriteLock([&] { + _includeItems = includeItems; + }); +} + +#endif // hifi_Pick_h diff --git a/interface/src/raypick/PickManager.h b/interface/src/raypick/PickManager.h new file mode 100644 index 0000000000..228631449f --- /dev/null +++ b/interface/src/raypick/PickManager.h @@ -0,0 +1,244 @@ +// +// PickManager.h +// interface/src/raypick +// +// Created by Sam Gondelman 10/16/2017 +// Copyright 2017 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_PickManager_h +#define hifi_PickManager_h + +#include + +#include "Pick.h" + +typedef struct RayCacheKey { + PickFilter::Flags mask; + QVector include; + QVector ignore; + + bool operator==(const RayCacheKey& other) const { + return (mask == other.mask && include == other.include && ignore == other.ignore); + } +} RayCacheKey; + +namespace std { + template <> + struct hash { + size_t operator()(const RayCacheKey& k) const { + return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); + } + }; +} + +// T is a mathematical representation of a Pick. +// For example: origin and direction for RayPick +template +class PickManager : protected ReadWriteLockable { + +public: + virtual void update(); + + RayPickResult getPrevPickResult(const QUuid& uid) const; + + void removePick(const QUuid& uid); + void enablePick(const QUuid& uid) const; + void disablePick(const QUuid& uid) const; + + void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; + void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; + void setIncludeItems(const QUuid& uid, const QVector& include) const; + +protected: + Pick::Pointer findPick(const QUuid& uid) const; + QHash::Pointer> _picks; + + typedef QHash> RayPickCache; + + // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer + bool checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key); + void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache); +}; + +template +RayPick::Pointer PickManager::findPick(const QUuid& uid) const { + return resultWithReadLock([&] { + if (_picks.contains(uid)) { + return _picks[uid]; + } + return RayPick::Pointer(); + }); +} + +template +bool PickManager::checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) { + if (cache.contains(pick) && cache[pick].find(key) != cache[pick].end()) { + if (cache[pick][key].distance < res.distance) { + res = cache[pick][key]; + } + return true; + } + return false; +} + +template +void PickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache) { + if (intersects) { + cache[pick][key] = resTemp; + if (resTemp.distance < res.distance) { + res = resTemp; + } + } else { + cache[pick][key] = RayPickResult(res.searchRay); + } +} + +template +void PickManager::update() { + RayPickCache results; + QHash::Pointer> cachedPicks; + withReadLock([&] { + cachedPicks = _picks; + }); + + for (const auto& uid : cachedPicks.keys()) { + Pick::Pointer pick = cachedPicks[uid]; + if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) { + continue; + } + + T mathematicalPick; + + { + bool valid; + mathematicalPick = pick->getPickRay(valid); + if (!valid) { + continue; + } + } + + RayPickResult res = RayPickResult(mathematicalPick); + + if (pick->getFilter().doesPickEntities()) { + RayToEntityIntersectionResult entityRes; + bool fromCache = true; + bool invisible = pick->getFilter().doesPickInvisible(); + bool nonCollidable = pick->getFilter().doesPickNonCollidable(); + RayCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { + entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), + pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); + fromCache = false; + } + + if (!fromCache) { + cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, mathematicalPick, entityRes.surfaceNormal), + entityKey, res, mathematicalPick, results); + } + } + + if (pick->getFilter().doesPickOverlays()) { + RayToOverlayIntersectionResult overlayRes; + bool fromCache = true; + bool invisible = pick->getFilter().doesPickInvisible(); + bool nonCollidable = pick->getFilter().doesPickNonCollidable(); + RayCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { + overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), + pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); + fromCache = false; + } + + if (!fromCache) { + cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, mathematicalPick, overlayRes.surfaceNormal), + overlayKey, res, mathematicalPick, results); + } + } + + if (pick->getFilter().doesPickAvatars()) { + RayCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { + RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick, + pick->getIncludeItemsAs(), pick->getIgnoreItemsAs()); + cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, mathematicalPick), avatarKey, res, mathematicalPick, results); + } + } + + // Can't intersect with HUD in desktop mode + if (pick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { + RayCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { + glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick.origin, mathematicalPick.direction); + cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(mathematicalPick.origin, hudRes), hudRes, mathematicalPick), hudKey, res, mathematicalPick, results); + } + } + + if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res.distance < pick->getMaxDistance())) { + pick->setPickResult(res); + } else { + pick->setPickResult(RayPickResult(mathematicalPick)); + } + } +} + +template +RayPickResult PickManager::getPrevPickResult(const QUuid& uid) const { + auto rayPick = findPick(uid); + if (rayPick) { + return rayPick->getPrevPickResult(); + } + return RayPickResult(); +} + +template +void PickManager::removePick(const QUuid& uid) { + withWriteLock([&] { + _picks.remove(uid); + }); +} + +template +void PickManager::enablePick(const QUuid& uid) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->enable(); + } +} + +template +void PickManager::disablePick(const QUuid& uid) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->disable(); + } +} + +template +void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->setPrecisionPicking(precisionPicking); + } +} + +template +void PickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->setIgnoreItems(ignore); + } +} + +template +void PickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->setIncludeItems(include); + } +} + + +#endif // hifi_PickManager_h \ No newline at end of file diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp new file mode 100644 index 0000000000..f12320ee35 --- /dev/null +++ b/interface/src/raypick/RayPick.cpp @@ -0,0 +1,39 @@ +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 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 "RayPick.h" + +#include "Application.h" +#include "avatar/AvatarManager.h" +#include "scripting/HMDScriptingInterface.h" +#include "DependencyManager.h" + +RayToEntityIntersectionResult RayPick::getEntityIntersection(const PickRay& pick, bool precisionPicking, + const QVector& entitiesToInclude, + const QVector& entitiesToIgnore, + bool visibleOnly, bool collidableOnly) { + return DependencyManager::get()->findRayIntersectionVector(pick, precisionPicking, + entitiesToInclude, entitiesToIgnore, visibleOnly, collidableOnly); +} + +RayToOverlayIntersectionResult RayPick::getOverlayIntersection(const PickRay& pick, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToIgnore, + bool visibleOnly, bool collidableOnly) { + return qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking, + overlaysToInclude, overlaysToIgnore, visibleOnly, collidableOnly); +} + +RayToAvatarIntersectionResult RayPick::getAvatarIntersection(const PickRay& pick, + const QVector& avatarsToInclude, + const QVector& avatarsToIgnore) { + return DependencyManager::get()->findRayIntersectionVector(pick, avatarsToInclude, avatarsToIgnore); +} + +glm::vec3 RayPick::getHUDIntersection(const PickRay& pick) { + return DependencyManager::get()->calculateRayUICollisionPoint(pick.origin, pick.direction); +} \ No newline at end of file diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h new file mode 100644 index 0000000000..92778e74a2 --- /dev/null +++ b/interface/src/raypick/RayPick.h @@ -0,0 +1,35 @@ +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 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_RayPick_h +#define hifi_RayPick_h + +#include "Pick.h" + +class EntityItemID; +class OverlayID; + +class RayPick : public Pick { + +public: + RayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : Pick(filter, maxDistance, enabled) {} + + RayToEntityIntersectionResult getEntityIntersection(const PickRay& pick, bool precisionPicking, + const QVector& entitiesToInclude, + const QVector& entitiesToIgnore, + bool visibleOnly, bool collidableOnly) override; + RayToOverlayIntersectionResult getOverlayIntersection(const PickRay& pick, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToIgnore, + bool visibleOnly, bool collidableOnly) override; + RayToAvatarIntersectionResult getAvatarIntersection(const PickRay& pick, + const QVector& avatarsToInclude, + const QVector& avatarsToIgnore) override; + glm::vec3 getHUDIntersection(const PickRay& pick) override; +}; + +#endif // hifi_RayPick_h diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index beb0075428..f4a45312bf 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -10,209 +10,33 @@ // #include "RayPickManager.h" -#include - -#include "Application.h" -#include "EntityScriptingInterface.h" -#include "ui/overlays/Overlays.h" -#include "avatar/AvatarManager.h" -#include "scripting/HMDScriptingInterface.h" -#include "DependencyManager.h" - +#include "StaticRayPick.h" #include "JointRayPick.h" #include "MouseRayPick.h" -bool RayPickManager::checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) { - if (cache.contains(ray) && cache[ray].find(key) != cache[ray].end()) { - if (cache[ray][key].distance < res.distance) { - res = cache[ray][key]; - } - return true; - } - return false; -} - -void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair& ray, RayPickCache& cache) { - if (intersects) { - cache[ray][key] = resTemp; - if (resTemp.distance < res.distance) { - res = resTemp; - } - } else { - cache[ray][key] = RayPickResult(res.searchRay); - } -} - -void RayPickManager::update() { - RayPickCache results; - QHash cachedRayPicks; - withReadLock([&] { - cachedRayPicks = _rayPicks; - }); - - for (const auto& uid : cachedRayPicks.keys()) { - std::shared_ptr rayPick = cachedRayPicks[uid]; - if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) { - continue; - } - - PickRay ray; - - { - bool valid; - ray = rayPick->getPickRay(valid); - if (!valid) { - continue; - } - } - - QPair rayKey = QPair(ray.origin, ray.direction); - RayPickResult res = RayPickResult(ray); - - if (rayPick->getFilter().doesPickEntities()) { - RayToEntityIntersectionResult entityRes; - bool fromCache = true; - bool invisible = rayPick->getFilter().doesPickInvisible(); - bool nonCollidable = rayPick->getFilter().doesPickNonCollidable(); - RayCacheKey entityKey = { rayPick->getFilter().getEntityFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(rayKey, results, res, entityKey)) { - entityRes = DependencyManager::get()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(), - rayPick->getIncludeItemsAs(), rayPick->getIgnoreItemsAs(), !invisible, !nonCollidable); - fromCache = false; - } - - if (!fromCache) { - cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal), - entityKey, res, rayKey, results); - } - } - - if (rayPick->getFilter().doesPickOverlays()) { - RayToOverlayIntersectionResult overlayRes; - bool fromCache = true; - bool invisible = rayPick->getFilter().doesPickInvisible(); - bool nonCollidable = rayPick->getFilter().doesPickNonCollidable(); - RayCacheKey overlayKey = { rayPick->getFilter().getOverlayFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(rayKey, results, res, overlayKey)) { - overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(), - rayPick->getIncludeItemsAs(), rayPick->getIgnoreItemsAs(), !invisible, !nonCollidable); - fromCache = false; - } - - if (!fromCache) { - cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal), - overlayKey, res, rayKey, results); - } - } - - if (rayPick->getFilter().doesPickAvatars()) { - RayCacheKey avatarKey = { rayPick->getFilter().getAvatarFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(rayKey, results, res, avatarKey)) { - RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(ray, - rayPick->getIncludeItemsAs(), rayPick->getIgnoreItemsAs()); - cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarKey, res, rayKey, results); - } - } - - // Can't intersect with HUD in desktop mode - if (rayPick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { - RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags(); - RayCacheKey hudKey = { rayPick->getFilter().getHUDFlags() }; - if (!checkAndCompareCachedResults(rayKey, results, res, hudKey)) { - glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(ray.origin, ray.direction); - cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudKey, res, rayKey, results); - } - } - - if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { - rayPick->setRayPickResult(res); - } else { - rayPick->setRayPickResult(RayPickResult(ray)); - } - } -} - -QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, float maxDistance, bool enabled) { +QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) { auto newRayPick = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); QUuid id = QUuid::createUuid(); withWriteLock([&] { - _rayPicks[id] = newRayPick; + _picks[id] = newRayPick; }); return id; } -QUuid RayPickManager::createRayPick(const RayPickFilter& filter, float maxDistance, bool enabled) { +QUuid RayPickManager::createRayPick(const PickFilter& filter, float maxDistance, bool enabled) { QUuid id = QUuid::createUuid(); auto newRayPick = std::make_shared(filter, maxDistance, enabled); withWriteLock([&] { - _rayPicks[id] = newRayPick; + _picks[id] = newRayPick; }); return id; } -QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, float maxDistance, bool enabled) { +QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) { QUuid id = QUuid::createUuid(); auto newRayPick = std::make_shared(position, direction, filter, maxDistance, enabled); withWriteLock([&] { - _rayPicks[id] = newRayPick; + _picks[id] = newRayPick; }); return id; -} - -void RayPickManager::removeRayPick(const QUuid& uid) { - withWriteLock([&] { - _rayPicks.remove(uid); - }); -} - -RayPick::Pointer RayPickManager::findRayPick(const QUuid& uid) const { - return resultWithReadLock([&] { - if (_rayPicks.contains(uid)) { - return _rayPicks[uid]; - } - return RayPick::Pointer(); - }); -} - -void RayPickManager::enableRayPick(const QUuid& uid) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->enable(); - } -} - -void RayPickManager::disableRayPick(const QUuid& uid) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->disable(); - } -} - -RayPickResult RayPickManager::getPrevRayPickResult(const QUuid& uid) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - return rayPick->getPrevRayPickResult(); - } - return RayPickResult(); -} - -void RayPickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->setPrecisionPicking(precisionPicking); - } -} - -void RayPickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->setIgnoreItems(ignore); - } -} - -void RayPickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->setIncludeItems(include); - } -} +} \ No newline at end of file diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index fd2c6f4a6b..7673e402f4 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -11,64 +11,16 @@ #ifndef hifi_RayPickManager_h #define hifi_RayPickManager_h - -#include -#include -#include - -#include - -#include -#include - +#include "PickManager.h" class RayPickResult; -typedef struct RayCacheKey { - RayPickFilter::Flags mask; - QVector include; - QVector ignore; - - bool operator==(const RayCacheKey& other) const { - return (mask == other.mask && include == other.include && ignore == other.ignore); - } -} RayCacheKey; - -namespace std { - template <> - struct hash { - size_t operator()(const RayCacheKey& k) const { - return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); - } - }; -} - -class RayPickManager : protected ReadWriteLockable { +class RayPickManager : public PickManager { public: - void update(); - - QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled); - QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled); - QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled); - void removeRayPick(const QUuid& uid); - void enableRayPick(const QUuid& uid) const; - void disableRayPick(const QUuid& uid) const; - RayPickResult getPrevRayPickResult(const QUuid& uid) const; - - void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; - void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; - void setIncludeItems(const QUuid& uid, const QVector& include) const; - -private: - RayPick::Pointer findRayPick(const QUuid& uid) const; - QHash _rayPicks; - - typedef QHash, std::unordered_map> RayPickCache; - - // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer - bool checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key); - void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair& ray, RayPickCache& cache); + QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled); + QUuid createRayPick(const PickFilter& filter, const float maxDistance, const bool enabled); + QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled); }; #endif // hifi_RayPickManager_h \ No newline at end of file diff --git a/libraries/pointers/src/pointers/rays/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp similarity index 73% rename from libraries/pointers/src/pointers/rays/StaticRayPick.cpp rename to interface/src/raypick/StaticRayPick.cpp index e507341021..5db054c2e4 100644 --- a/libraries/pointers/src/pointers/rays/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -7,13 +7,13 @@ // #include "StaticRayPick.h" -StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) : +StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _pickRay(position, direction) { } -const PickRay StaticRayPick::getPickRay(bool& valid) const { +const PickRay StaticRayPick::getMathematicalPick(bool& valid) const { valid = true; return _pickRay; } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/rays/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h similarity index 75% rename from libraries/pointers/src/pointers/rays/StaticRayPick.h rename to interface/src/raypick/StaticRayPick.h index de5ec234a5..c26ea386d6 100644 --- a/libraries/pointers/src/pointers/rays/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -13,9 +13,9 @@ class StaticRayPick : public RayPick { public: - StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) const override; + const PickRay getMathematicalPick(bool& valid) const override; private: PickRay _pickRay; diff --git a/libraries/pointers/src/pointers/rays/RayPick.cpp b/libraries/pointers/src/pointers/rays/RayPick.cpp deleted file mode 100644 index 36756cdb79..0000000000 --- a/libraries/pointers/src/pointers/rays/RayPick.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 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 "RayPick.h" - -const RayPickFilter RayPickFilter::NOTHING; - -RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) : - _filter(filter), - _maxDistance(maxDistance), - _enabled(enabled) -{ -} - -void RayPick::enable(bool enabled) { - withWriteLock([&] { - _enabled = enabled; - }); -} - -RayPickFilter RayPick::getFilter() const { - return resultWithReadLock([&] { - return _filter; - }); -} - -float RayPick::getMaxDistance() const { - return _maxDistance; -} - -bool RayPick::isEnabled() const { - return _enabled; -} - -void RayPick::setPrecisionPicking(bool precisionPicking) { - withWriteLock([&]{ - _filter.setFlag(RayPickFilter::PICK_COARSE, !precisionPicking); - }); -} - -void RayPick::setRayPickResult(const RayPickResult& rayPickResult) { - withWriteLock([&] { - _prevResult = rayPickResult; - }); -} - -QVector RayPick::getIgnoreItems() const { - return _ignoreItems; -} - -QVector RayPick::getIncludeItems() const { - return _includeItems; -} - -RayPickResult RayPick::getPrevRayPickResult() const { - return resultWithReadLock([&] { - return _prevResult; - }); -} - -void RayPick::setIgnoreItems(const QVector& ignoreItems) { - withWriteLock([&] { - _ignoreItems = ignoreItems; - }); -} - -void RayPick::setIncludeItems(const QVector& includeItems) { - withWriteLock([&] { - _includeItems = includeItems; - }); -} diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 7b7d8d8f47..01b59f27e0 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -131,7 +131,22 @@ public: PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {} glm::vec3 origin; glm::vec3 direction; + + bool operator==(const PickRay& other) const { + return (origin == other.origin && direction == other.direction); + } }; +namespace std { + template <> + struct hash { + size_t operator()(const glm::vec3& a) const { + return ((hash()(a.x) ^ (hash()(a.y) << 1)) >> 1) ^ (hash()(a.z) << 1); + } + }; +} +uint qHash(const PickRay& a) { + return (uint)(std::hash()(a.origin) ^ (std::hash()(a.direction) << 1)); +} Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);