mirror of
https://github.com/lubosz/overte.git
synced 2025-04-10 08:57:12 +02:00
pickmanager wip
This commit is contained in:
parent
429905de51
commit
596be8ec27
15 changed files with 487 additions and 345 deletions
|
@ -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<AvatarManager>()->getMyAvatar();
|
||||
int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName));
|
||||
bool useAvatarHead = _jointName == "Avatar";
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
#ifndef hifi_JointRayPick_h
|
||||
#define hifi_JointRayPick_h
|
||||
|
||||
#include <pointers/rays/RayPick.h>
|
||||
#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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
#ifndef hifi_MouseRayPick_h
|
||||
#define hifi_MouseRayPick_h
|
||||
|
||||
#include <pointers/rays/RayPick.h>
|
||||
#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
|
||||
|
|
10
interface/src/raypick/Pick.cpp
Normal file
10
interface/src/raypick/Pick.cpp
Normal file
|
@ -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;
|
|
@ -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 <stdint.h>
|
||||
#include <bitset>
|
||||
|
@ -16,7 +16,10 @@
|
|||
#include <RegisteredMetaTypes.h>
|
||||
#include <shared/ReadWriteLockable.h>
|
||||
|
||||
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<typename T>
|
||||
class Pick : protected ReadWriteLockable {
|
||||
|
||||
public:
|
||||
using Pointer = std::shared_ptr<RayPick>;
|
||||
using Pointer = std::shared_ptr<Pick<T>>;
|
||||
|
||||
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<EntityItemID>& entitiesToInclude,
|
||||
const QVector<EntityItemID>& entitiesToIgnore,
|
||||
bool visibleOnly, bool collidableOnly) = 0;
|
||||
virtual RayToOverlayIntersectionResult getOverlayIntersection(const T& pick, bool precisionPicking,
|
||||
const QVector<OverlayID>& overlaysToInclude,
|
||||
const QVector<OverlayID>& overlaysToIgnore,
|
||||
bool visibleOnly, bool collidableOnly) = 0;
|
||||
virtual RayToAvatarIntersectionResult getAvatarIntersection(const T& pick,
|
||||
const QVector<EntityItemID>& avatarsToInclude,
|
||||
const QVector<EntityItemID>& 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<QUuid> getIgnoreItems() const;
|
||||
QVector<QUuid> getIncludeItems() const;
|
||||
|
@ -144,7 +160,7 @@ public:
|
|||
void setIncludeItems(const QVector<QUuid>& items);
|
||||
|
||||
private:
|
||||
RayPickFilter _filter;
|
||||
PickFilter _filter;
|
||||
const float _maxDistance;
|
||||
bool _enabled;
|
||||
RayPickResult _prevResult;
|
||||
|
@ -153,4 +169,87 @@ private:
|
|||
QVector<QUuid> _includeItems;
|
||||
};
|
||||
|
||||
#endif // hifi_RayPick_h
|
||||
|
||||
template<typename T>
|
||||
Pick<T>::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) :
|
||||
_filter(filter),
|
||||
_maxDistance(maxDistance),
|
||||
_enabled(enabled) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Pick<T>::enable(bool enabled) {
|
||||
withWriteLock([&] {
|
||||
_enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PickFilter Pick<T>::getFilter() const {
|
||||
return resultWithReadLock<PickFilter>([&] {
|
||||
return _filter;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
float Pick<T>::getMaxDistance() const {
|
||||
return _maxDistance;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Pick<T>::isEnabled() const {
|
||||
withReadLock([&]) {
|
||||
return _enabled;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Pick<T>::setPrecisionPicking(bool precisionPicking) {
|
||||
withWriteLock([&] {
|
||||
_filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Pick<T>::setPickResult(const RayPickResult& PickResult) {
|
||||
withWriteLock([&] {
|
||||
_prevResult = PickResult;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QVector<QUuid> Pick<T>::getIgnoreItems() const {
|
||||
withReadLock([&]) {
|
||||
return _ignoreItems;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QVector<QUuid> Pick<T>::getIncludeItems() const {
|
||||
withReadLock([&]) {
|
||||
return _includeItems;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RayPickResult Pick<T>::getPrevPickResult() const {
|
||||
return resultWithReadLock<RayPickResult>([&] {
|
||||
return _prevResult;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Pick<T>::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
|
||||
withWriteLock([&] {
|
||||
_ignoreItems = ignoreItems;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Pick<T>::setIncludeItems(const QVector<QUuid>& includeItems) {
|
||||
withWriteLock([&] {
|
||||
_includeItems = includeItems;
|
||||
});
|
||||
}
|
||||
|
||||
#endif // hifi_Pick_h
|
244
interface/src/raypick/PickManager.h
Normal file
244
interface/src/raypick/PickManager.h
Normal file
|
@ -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 <unordered_map>
|
||||
|
||||
#include "Pick.h"
|
||||
|
||||
typedef struct RayCacheKey {
|
||||
PickFilter::Flags mask;
|
||||
QVector<QUuid> include;
|
||||
QVector<QUuid> ignore;
|
||||
|
||||
bool operator==(const RayCacheKey& other) const {
|
||||
return (mask == other.mask && include == other.include && ignore == other.ignore);
|
||||
}
|
||||
} RayCacheKey;
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<RayCacheKey> {
|
||||
size_t operator()(const RayCacheKey& k) const {
|
||||
return ((hash<PickFilter::Flags>()(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<typename T>
|
||||
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<QUuid>& ignore) const;
|
||||
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const;
|
||||
|
||||
protected:
|
||||
Pick<T>::Pointer findPick(const QUuid& uid) const;
|
||||
QHash<QUuid, Pick<T>::Pointer> _picks;
|
||||
|
||||
typedef QHash<T, std::unordered_map<RayCacheKey, RayPickResult>> 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<typename T>
|
||||
RayPick::Pointer PickManager<T>::findPick(const QUuid& uid) const {
|
||||
return resultWithReadLock<RayPick::Pointer>([&] {
|
||||
if (_picks.contains(uid)) {
|
||||
return _picks[uid];
|
||||
}
|
||||
return RayPick::Pointer();
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool PickManager<T>::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<typename T>
|
||||
void PickManager<T>::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<typename T>
|
||||
void PickManager<T>::update() {
|
||||
RayPickCache results;
|
||||
QHash<QUuid, Pick<T>::Pointer> cachedPicks;
|
||||
withReadLock([&] {
|
||||
cachedPicks = _picks;
|
||||
});
|
||||
|
||||
for (const auto& uid : cachedPicks.keys()) {
|
||||
Pick<T>::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<EntityItemID>(), pick->getIgnoreItemsAs<EntityItemID>(), !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<OverlayID>(), pick->getIgnoreItemsAs<OverlayID>(), !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<EntityItemID>(), pick->getIgnoreItemsAs<EntityItemID>());
|
||||
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<HMDScriptingInterface>()->isHMDMode()) {
|
||||
RayCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
|
||||
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<typename T>
|
||||
RayPickResult PickManager<T>::getPrevPickResult(const QUuid& uid) const {
|
||||
auto rayPick = findPick(uid);
|
||||
if (rayPick) {
|
||||
return rayPick->getPrevPickResult();
|
||||
}
|
||||
return RayPickResult();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PickManager<T>::removePick(const QUuid& uid) {
|
||||
withWriteLock([&] {
|
||||
_picks.remove(uid);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PickManager<T>::enablePick(const QUuid& uid) const {
|
||||
auto rayPick = findPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->enable();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PickManager<T>::disablePick(const QUuid& uid) const {
|
||||
auto rayPick = findPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->disable();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PickManager<T>::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
|
||||
auto rayPick = findPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->setPrecisionPicking(precisionPicking);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PickManager<T>::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
|
||||
auto rayPick = findPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->setIgnoreItems(ignore);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PickManager<T>::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
|
||||
auto rayPick = findPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->setIncludeItems(include);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // hifi_PickManager_h
|
39
interface/src/raypick/RayPick.cpp
Normal file
39
interface/src/raypick/RayPick.cpp
Normal file
|
@ -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<EntityItemID>& entitiesToInclude,
|
||||
const QVector<EntityItemID>& entitiesToIgnore,
|
||||
bool visibleOnly, bool collidableOnly) {
|
||||
return DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(pick, precisionPicking,
|
||||
entitiesToInclude, entitiesToIgnore, visibleOnly, collidableOnly);
|
||||
}
|
||||
|
||||
RayToOverlayIntersectionResult RayPick::getOverlayIntersection(const PickRay& pick, bool precisionPicking,
|
||||
const QVector<OverlayID>& overlaysToInclude,
|
||||
const QVector<OverlayID>& overlaysToIgnore,
|
||||
bool visibleOnly, bool collidableOnly) {
|
||||
return qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking,
|
||||
overlaysToInclude, overlaysToIgnore, visibleOnly, collidableOnly);
|
||||
}
|
||||
|
||||
RayToAvatarIntersectionResult RayPick::getAvatarIntersection(const PickRay& pick,
|
||||
const QVector<EntityItemID>& avatarsToInclude,
|
||||
const QVector<EntityItemID>& avatarsToIgnore) {
|
||||
return DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, avatarsToInclude, avatarsToIgnore);
|
||||
}
|
||||
|
||||
glm::vec3 RayPick::getHUDIntersection(const PickRay& pick) {
|
||||
return DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(pick.origin, pick.direction);
|
||||
}
|
35
interface/src/raypick/RayPick.h
Normal file
35
interface/src/raypick/RayPick.h
Normal file
|
@ -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<PickRay> {
|
||||
|
||||
public:
|
||||
RayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : Pick(filter, maxDistance, enabled) {}
|
||||
|
||||
RayToEntityIntersectionResult getEntityIntersection(const PickRay& pick, bool precisionPicking,
|
||||
const QVector<EntityItemID>& entitiesToInclude,
|
||||
const QVector<EntityItemID>& entitiesToIgnore,
|
||||
bool visibleOnly, bool collidableOnly) override;
|
||||
RayToOverlayIntersectionResult getOverlayIntersection(const PickRay& pick, bool precisionPicking,
|
||||
const QVector<OverlayID>& overlaysToInclude,
|
||||
const QVector<OverlayID>& overlaysToIgnore,
|
||||
bool visibleOnly, bool collidableOnly) override;
|
||||
RayToAvatarIntersectionResult getAvatarIntersection(const PickRay& pick,
|
||||
const QVector<EntityItemID>& avatarsToInclude,
|
||||
const QVector<EntityItemID>& avatarsToIgnore) override;
|
||||
glm::vec3 getHUDIntersection(const PickRay& pick) override;
|
||||
};
|
||||
|
||||
#endif // hifi_RayPick_h
|
|
@ -10,209 +10,33 @@
|
|||
//
|
||||
#include "RayPickManager.h"
|
||||
|
||||
#include <pointers/rays/StaticRayPick.h>
|
||||
|
||||
#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<glm::vec3, glm::vec3>& 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<glm::vec3, glm::vec3>& 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<QUuid, RayPick::Pointer> cachedRayPicks;
|
||||
withReadLock([&] {
|
||||
cachedRayPicks = _rayPicks;
|
||||
});
|
||||
|
||||
for (const auto& uid : cachedRayPicks.keys()) {
|
||||
std::shared_ptr<RayPick> 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<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(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<EntityScriptingInterface>()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
|
||||
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>(), !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<OverlayID>(), rayPick->getIgnoreItemsAs<OverlayID>(), !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<AvatarManager>()->findRayIntersectionVector(ray,
|
||||
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>());
|
||||
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<HMDScriptingInterface>()->isHMDMode()) {
|
||||
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
|
||||
RayCacheKey hudKey = { rayPick->getFilter().getHUDFlags() };
|
||||
if (!checkAndCompareCachedResults(rayKey, results, res, hudKey)) {
|
||||
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->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<JointRayPick>(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<MouseRayPick>(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<StaticRayPick>(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<RayPick::Pointer>([&] {
|
||||
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<QUuid>& ignore) const {
|
||||
auto rayPick = findRayPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->setIgnoreItems(ignore);
|
||||
}
|
||||
}
|
||||
|
||||
void RayPickManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
|
||||
auto rayPick = findRayPick(uid);
|
||||
if (rayPick) {
|
||||
rayPick->setIncludeItems(include);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,64 +11,16 @@
|
|||
#ifndef hifi_RayPickManager_h
|
||||
#define hifi_RayPickManager_h
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <pointers/rays/RayPick.h>
|
||||
|
||||
#include "PickManager.h"
|
||||
|
||||
class RayPickResult;
|
||||
|
||||
typedef struct RayCacheKey {
|
||||
RayPickFilter::Flags mask;
|
||||
QVector<QUuid> include;
|
||||
QVector<QUuid> ignore;
|
||||
|
||||
bool operator==(const RayCacheKey& other) const {
|
||||
return (mask == other.mask && include == other.include && ignore == other.ignore);
|
||||
}
|
||||
} RayCacheKey;
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<RayCacheKey> {
|
||||
size_t operator()(const RayCacheKey& k) const {
|
||||
return ((hash<RayPickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class RayPickManager : protected ReadWriteLockable {
|
||||
class RayPickManager : public PickManager<PickRay> {
|
||||
|
||||
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<QUuid>& ignore) const;
|
||||
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const;
|
||||
|
||||
private:
|
||||
RayPick::Pointer findRayPick(const QUuid& uid) const;
|
||||
QHash<QUuid, RayPick::Pointer> _rayPicks;
|
||||
|
||||
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayCacheKey, RayPickResult>> 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<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key);
|
||||
void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& 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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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<RayPickFilter>([&] {
|
||||
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<QUuid> RayPick::getIgnoreItems() const {
|
||||
return _ignoreItems;
|
||||
}
|
||||
|
||||
QVector<QUuid> RayPick::getIncludeItems() const {
|
||||
return _includeItems;
|
||||
}
|
||||
|
||||
RayPickResult RayPick::getPrevRayPickResult() const {
|
||||
return resultWithReadLock<RayPickResult>([&] {
|
||||
return _prevResult;
|
||||
});
|
||||
}
|
||||
|
||||
void RayPick::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
|
||||
withWriteLock([&] {
|
||||
_ignoreItems = ignoreItems;
|
||||
});
|
||||
}
|
||||
|
||||
void RayPick::setIncludeItems(const QVector<QUuid>& includeItems) {
|
||||
withWriteLock([&] {
|
||||
_includeItems = includeItems;
|
||||
});
|
||||
}
|
|
@ -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<glm::vec3> {
|
||||
size_t operator()(const glm::vec3& a) const {
|
||||
return ((hash<float>()(a.x) ^ (hash<float>()(a.y) << 1)) >> 1) ^ (hash<float>()(a.z) << 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
uint qHash(const PickRay& a) {
|
||||
return (uint)(std::hash<glm::vec3>()(a.origin) ^ (std::hash<glm::vec3>()(a.direction) << 1));
|
||||
}
|
||||
Q_DECLARE_METATYPE(PickRay)
|
||||
QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay);
|
||||
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);
|
||||
|
|
Loading…
Reference in a new issue