non-templated pickresult wip

This commit is contained in:
SamGondelman 2017-10-18 18:43:56 -07:00
parent 640ad514bc
commit 3572f7f5db
17 changed files with 217 additions and 206 deletions

View file

@ -1823,14 +1823,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
0.0f, true));
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickResultOperator([&](QUuid rayPickID) {
RayToEntityIntersectionResult entityResult;
RayPickResult result = _rayPickManager.getPrevPickResult(rayPickID);
entityResult.intersects = result.type != RayPickScriptingInterface::INTERSECTED_NONE();
if (entityResult.intersects) {
entityResult.intersection = result.intersection;
entityResult.distance = result.distance;
entityResult.surfaceNormal = result.surfaceNormal;
entityResult.entityID = result.objectID;
entityResult.entity = DependencyManager::get<EntityTreeRenderer>()->getTree()->findEntityByID(entityResult.entityID);
entityResult.intersects = false;
QVariantMap result = _rayPickManager.getPrevPickResult(rayPickID);
if (result["type"].isValid()) {
entityResult.intersects = result["type"] != RayPickScriptingInterface::INTERSECTED_NONE();
if (entityResult.intersects) {
entityResult.intersection = vec3FromVariant(result["intersection"]);
entityResult.distance = result["distance"].toFloat();
entityResult.surfaceNormal = vec3FromVariant(result["surfaceNormal"]);
entityResult.entityID = result["objectID"].toUuid();
entityResult.entity = DependencyManager::get<EntityTreeRenderer>()->getTree()->findEntityByID(entityResult.entityID);
}
}
return entityResult;
});

View file

@ -12,7 +12,6 @@
#include "Application.h"
#include "avatar/AvatarManager.h"
#include "RayPickScriptingInterface.h"
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) :
@ -101,7 +100,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
}
}
const RayPickResult LaserPointer::getPrevRayPickResult() {
const QVariantMap LaserPointer::getPrevRayPickResult() {
return qApp->getRayPickManager().getPrevPickResult(_rayPickUID);
}
@ -198,15 +197,18 @@ void LaserPointer::disableRenderState(const RenderState& renderState) {
void LaserPointer::update() {
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
withReadLock([&] {
RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID);
QVariantMap prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID);
IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt());
PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap());
QUuid uid = prevRayPickResult["objectID"].toUuid();
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
(type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult["distance"].toFloat();
updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false);
disableRenderState(_defaultRenderStates[_currentRenderState].second);
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true);
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay, true);
} else if (!_currentRenderState.empty()) {
disableRenderState(_renderStates[_currentRenderState]);
disableRenderState(_defaultRenderStates[_currentRenderState].second);

View file

@ -19,7 +19,7 @@
#include "ui/overlays/Overlay.h"
class RayPickResult;
#include "RayPickScriptingInterface.h"
class RenderState {
@ -61,7 +61,7 @@ public:
QUuid getRayUID() { return _rayPickUID; }
void enable();
void disable();
const RayPickResult getPrevRayPickResult();
const QVariantMap getPrevRayPickResult();
void setRenderState(const std::string& state);
// You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays.

View file

@ -67,12 +67,12 @@ void LaserPointerManager::editRenderState(const QUuid& uid, const std::string& s
}
}
const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const {
const QVariantMap LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
return laserPointer->getPrevRayPickResult();
}
return RayPickResult();
return QVariantMap();
}
void LaserPointerManager::update() {

View file

@ -18,9 +18,6 @@
#include "LaserPointer.h"
class RayPickResult;
class LaserPointerManager : protected ReadWriteLockable {
public:
@ -31,7 +28,7 @@ public:
void disableLaserPointer(const QUuid& uid) const;
void setRenderState(const QUuid& uid, const std::string& renderState) const;
void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const;
const RayPickResult getPrevRayPickResult(const QUuid& uid) const;
const QVariantMap getPrevRayPickResult(const QUuid& uid) const;
void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const;
void setLaserLength(const QUuid& uid, const float laserLength) const;

View file

@ -28,7 +28,7 @@ public slots:
Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().removeLaserPointer(uid); }
Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const;
Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { qApp->getLaserPointerManager().setRenderState(uid, renderState.toStdString()); }
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) const { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); }

View file

@ -8,32 +8,44 @@
#include "RayPick.h"
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.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);
PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) {
RayToEntityIntersectionResult entityRes =
DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(pick, !getFilter().doesPickCoarse(),
getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
if (entityRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
}
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);
PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
RayToOverlayIntersectionResult overlayRes =
qApp->getOverlays().findRayIntersectionVector(pick, !getFilter().doesPickCoarse(),
getIncludeItemsAs<OverlayID>(), getIgnoreItemsAs<OverlayID>(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
if (overlayRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, pick, overlayRes.surfaceNormal);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
}
RayToAvatarIntersectionResult RayPick::getAvatarIntersection(const PickRay& pick,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToIgnore) {
return DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, avatarsToInclude, avatarsToIgnore);
PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (avatarRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
}
glm::vec3 RayPick::getHUDIntersection(const PickRay& pick) {
return DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(pick.origin, pick.direction);
PickResultPointer RayPick::getHUDIntersection(const PickRay& pick) {
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(pick.origin, pick.direction);
return std::make_shared<RayPickResult>(IntersectionType::HUD, QUuid(), glm::distance(pick.origin, hudRes), hudRes, pick);
}

View file

@ -8,28 +8,72 @@
#ifndef hifi_RayPick_h
#define hifi_RayPick_h
#include "Pick.h"
#include <RegisteredMetaTypes.h>
#include <pointers/Pick.h>
class EntityItemID;
class OverlayID;
class RayPickResult : public PickResult {
public:
RayPickResult() {}
RayPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {}
RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) :
PickResult(searchRay.toVariantMap()), type(type), intersects(type != NONE), objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) {
}
RayPickResult(const RayPickResult& rayPickResult) : PickResult(rayPickResult.pickVariant) {
type = rayPickResult.type;
intersects = rayPickResult.intersects;
objectID = rayPickResult.objectID;
distance = rayPickResult.distance;
intersection = rayPickResult.intersection;
surfaceNormal = rayPickResult.surfaceNormal;
}
IntersectionType type { NONE };
bool intersects { false };
QUuid objectID;
float distance { FLT_MAX };
glm::vec3 intersection { NAN };
glm::vec3 surfaceNormal { NAN };
virtual QVariantMap toVariantMap() const override {
QVariantMap toReturn;
toReturn["type"] = type;
toReturn["intersects"] = intersects;
toReturn["objectID"] = objectID;
toReturn["distance"] = distance;
toReturn["intersection"] = vec3toVariant(intersection);
toReturn["surfaceNormal"] = vec3toVariant(surfaceNormal);
toReturn["searchRay"] = PickResult::toVariantMap();
return toReturn;
}
bool doesIntersect() const override { return intersects; }
bool checkOrFilterAgainstMaxDistance(float maxDistance) override { return distance < maxDistance; }
PickResultPointer compareAndProcessNewResult(const PickResultPointer newRes) override {
auto newRayRes = std::static_pointer_cast<RayPickResult>(newRes);
if (newRayRes->distance < distance) {
return std::make_shared<RayPickResult>(*newRayRes);
} else {
return std::make_shared<RayPickResult>(*this);
}
}
};
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;
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { return std::make_shared<RayPickResult>(pickVariant); }
PickResultPointer getEntityIntersection(const PickRay& pick) override;
PickResultPointer getOverlayIntersection(const PickRay& pick) override;
PickResultPointer getAvatarIntersection(const PickRay& pick) override;
PickResultPointer getHUDIntersection(const PickRay& pick) override;
};
#endif // hifi_RayPick_h

View file

@ -1,7 +1,4 @@
//
// RayPickManager.cpp
// interface/src/raypick
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//

View file

@ -1,7 +1,4 @@
//
// RayPickManager.h
// interface/src/raypick
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
@ -11,9 +8,8 @@
#ifndef hifi_RayPickManager_h
#define hifi_RayPickManager_h
#include "PickManager.h"
class RayPickResult;
#include <pointers/PickManager.h>
#include "RegisteredMetaTypes.h"
class RayPickManager : public PickManager<PickRay> {

View file

@ -78,7 +78,7 @@ void RayPickScriptingInterface::removeRayPick(const QUuid& uid) {
qApp->getRayPickManager().removePick(uid);
}
RayPickResult RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) {
QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) {
return qApp->getRayPickManager().getPrevPickResult(uid);
}

View file

@ -40,26 +40,26 @@ public slots:
Q_INVOKABLE void enableRayPick(const QUuid& uid);
Q_INVOKABLE void disableRayPick(const QUuid& uid);
Q_INVOKABLE void removeRayPick(const QUuid& uid);
Q_INVOKABLE RayPickResult getPrevRayPickResult(const QUuid& uid);
Q_INVOKABLE QVariantMap getPrevRayPickResult(const QUuid& uid);
Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking);
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities);
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities);
static unsigned int PICK_NOTHING() { return 0; }
static unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); }
static unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); }
static unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); }
static unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); }
static unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); }
static unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); }
static unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); }
static unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); }
static unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; }
static unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; }
static unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; }
static unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; }
static unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; }
static constexpr unsigned int PICK_NOTHING() { return 0; }
static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); }
static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); }
static constexpr unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); }
static constexpr unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); }
static constexpr unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); }
static constexpr unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); }
static constexpr unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); }
static constexpr unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); }
static constexpr unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; }
static constexpr unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; }
static constexpr unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; }
static constexpr unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; }
static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; }
};
#endif // hifi_RayPickScriptingInterface_h

View file

@ -13,12 +13,18 @@
#include <bitset>
#include <QtCore/QUuid>
#include <QVector>
#include <QVariant>
#include <RegisteredMetaTypes.h>
#include <shared/ReadWriteLockable.h>
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
enum IntersectionType {
NONE = 0,
ENTITY,
OVERLAY,
AVATAR,
HUD
};
class PickFilter {
public:
@ -98,6 +104,31 @@ public:
static const PickFilter NOTHING;
};
class PickResult {
public:
PickResult() {}
PickResult(const QVariantMap& pickVariant) : pickVariant(pickVariant) {}
virtual QVariantMap toVariantMap() const {
return pickVariant;
}
virtual bool doesIntersect() const = 0;
// for example: if we want the closest result, compare based on distance
// if we want all results, combine them
// must return a new pointer
virtual std::shared_ptr<PickResult> compareAndProcessNewResult(const std::shared_ptr<PickResult> newRes) = 0;
// returns true if this result contains any valid results with distance < maxDistance
// can also filter out results with distance >= maxDistance
virtual bool checkOrFilterAgainstMaxDistance(float maxDistance) = 0;
QVariantMap pickVariant;
};
using PickResultPointer = std::shared_ptr<PickResult>;
template<typename T>
class Pick : protected ReadWriteLockable {
@ -105,18 +136,11 @@ public:
Pick(const PickFilter& filter, const float maxDistance, const bool enabled);
virtual const T getMathematicalPick() 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;
virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0;
virtual PickResultPointer getEntityIntersection(const T& pick) = 0;
virtual PickResultPointer getOverlayIntersection(const T& pick) = 0;
virtual PickResultPointer getAvatarIntersection(const T& pick) = 0;
virtual PickResultPointer getHUDIntersection(const T& pick) = 0;
void enable(bool enabled = true);
void disable() { enable(false); }
@ -124,11 +148,11 @@ public:
PickFilter getFilter() const;
float getMaxDistance() const;
bool isEnabled() const;
RayPickResult getPrevPickResult() const;
void setPrecisionPicking(bool precisionPicking);
void setPickResult(const RayPickResult& rayPickResult);
PickResultPointer getPrevPickResult() const;
void setPickResult(const PickResultPointer& pickResult);
QVector<QUuid> getIgnoreItems() const;
QVector<QUuid> getIncludeItems() const;
@ -162,7 +186,7 @@ private:
PickFilter _filter;
const float _maxDistance;
bool _enabled;
RayPickResult _prevResult;
PickResultPointer _prevResult;
QVector<QUuid> _ignoreItems;
QVector<QUuid> _includeItems;
@ -209,9 +233,9 @@ void Pick<T>::setPrecisionPicking(bool precisionPicking) {
}
template<typename T>
void Pick<T>::setPickResult(const RayPickResult& PickResult) {
void Pick<T>::setPickResult(const PickResultPointer& pickResult) {
withWriteLock([&] {
_prevResult = PickResult;
_prevResult = pickResult;
});
}
@ -230,8 +254,8 @@ QVector<QUuid> Pick<T>::getIncludeItems() const {
}
template<typename T>
RayPickResult Pick<T>::getPrevPickResult() const {
return resultWithReadLock<RayPickResult>([&] {
PickResultPointer Pick<T>::getPrevPickResult() const {
return resultWithReadLock<PickResultPointer>([&] {
return _prevResult;
});
}

View file

@ -1,7 +1,4 @@
//
// PickManager.h
// interface/src/raypick
//
// Created by Sam Gondelman 10/16/2017
// Copyright 2017 High Fidelity, Inc.
//
@ -36,16 +33,20 @@ namespace std {
};
}
// T is a mathematical representation of a Pick.
// For example: PickRay for RayPick
// TODO: add another template type to replace RayPickResult with a generalized PickResult
// T is a mathematical representation of a Pick
// For example: RayPicks use T = PickRay
// T needs have the following functions defined:
// - operator bool() const
// - bool operator==(const T& other) const
// - QVariantMap toVariantMap() const
// - an std::hash size_t operator()(const T& a) const
template<typename T>
class PickManager : protected ReadWriteLockable {
public:
virtual void update();
RayPickResult getPrevPickResult(const QUuid& uid) const;
QVariantMap getPrevPickResult(const QUuid& uid) const;
QUuid addPick(const std::shared_ptr<Pick<T>> pick);
void removePick(const QUuid& uid);
@ -60,11 +61,11 @@ protected:
std::shared_ptr<Pick<T>> findPick(const QUuid& uid) const;
QHash<QUuid, std::shared_ptr<Pick<T>>> _picks;
typedef std::unordered_map<T, std::unordered_map<PickCacheKey, RayPickResult>> PickCache;
typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
// 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, PickCache& cache, RayPickResult& res, const PickCacheKey& key);
void cacheResult(const bool intersects, const RayPickResult& resTemp, const PickCacheKey& key, RayPickResult& res, T& pick, PickCache& cache);
// Returns true if this pick exists in the cache, and if it does, update res if the cached result is closer
bool checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key);
void cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr<Pick<T>> pick);
};
template<typename T>
@ -78,25 +79,21 @@ std::shared_ptr<Pick<T>> PickManager<T>::findPick(const QUuid& uid) const {
}
template<typename T>
bool PickManager<T>::checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key) {
bool PickManager<T>::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key) {
if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) {
if (cache[pick][key].distance < res.distance) {
res = cache[pick][key];
}
res = res->compareAndProcessNewResult(cache[pick][key]);
return true;
}
return false;
}
template<typename T>
void PickManager<T>::cacheResult(const bool intersects, const RayPickResult& resTemp, const PickCacheKey& key, RayPickResult& res, T& pick, PickCache& cache) {
void PickManager<T>::cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr<Pick<T>> pick) {
if (intersects) {
cache[pick][key] = resTemp;
if (resTemp.distance < res.distance) {
res = resTemp;
}
cache[mathPick][key] = resTemp;
res = res->compareAndProcessNewResult(resTemp);
} else {
cache[pick][key] = RayPickResult(res.searchRay);
cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap());
}
}
@ -120,50 +117,29 @@ void PickManager<T>::update() {
continue;
}
RayPickResult res = RayPickResult(mathematicalPick);
PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap());
if (pick->getFilter().doesPickEntities()) {
RayToEntityIntersectionResult entityRes;
bool fromCache = true;
bool invisible = pick->getFilter().doesPickInvisible();
bool nonCollidable = pick->getFilter().doesPickNonCollidable();
PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(),
pick->(template getIncludeItemsAs<EntityItemID>()), (template 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);
PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick);
cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick);
}
}
if (pick->getFilter().doesPickOverlays()) {
RayToOverlayIntersectionResult overlayRes;
bool fromCache = true;
bool invisible = pick->getFilter().doesPickInvisible();
bool nonCollidable = pick->getFilter().doesPickNonCollidable();
PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) {
overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(),
pick->(template getIncludeItemsAs<OverlayID>()), pick->(template 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);
PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick);
cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick);
}
}
if (pick->getFilter().doesPickAvatars()) {
PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) {
RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick,
pick->(template getIncludeItemsAs<EntityItemID>()), pick->(template getIgnoreItemsAs<EntityItemID>()));
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, mathematicalPick), avatarKey, res, mathematicalPick, results);
PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick);
cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick);
}
}
@ -171,26 +147,26 @@ void PickManager<T>::update() {
if (pick->getFilter().doesPickHUD() && DependencyManager::get<HMDScriptingInterface>()->isHMDMode()) {
PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick);
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(mathematicalPick.origin, hudRes), hudRes, mathematicalPick), hudKey, res, mathematicalPick, results);
PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick);
cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick);
}
}
if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res.distance < pick->getMaxDistance())) {
if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) {
pick->setPickResult(res);
} else {
pick->setPickResult(RayPickResult(mathematicalPick));
pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap()));
}
}
}
template<typename T>
RayPickResult PickManager<T>::getPrevPickResult(const QUuid& uid) const {
QVariantMap PickManager<T>::getPrevPickResult(const QUuid& uid) const {
auto pick = findPick(uid);
if (pick) {
return pick->getPrevPickResult();
if (pick && pick->getPrevPickResult()) {
return pick->getPrevPickResult()->toVariantMap();
}
return RayPickResult();
return QVariantMap();
}
template<typename T>

View file

@ -34,7 +34,6 @@ int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();
int quatMetaTypeId = qRegisterMetaType<glm::quat>();
int xColorMetaTypeId = qRegisterMetaType<xColor>();
int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
int rayPickResultMetaTypeId = qRegisterMetaType<RayPickResult>();
int collisionMetaTypeId = qRegisterMetaType<Collision>();
int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl,QString>>();
int socketErrorMetaTypeId = qRegisterMetaType<QAbstractSocket::SocketError>();
@ -57,7 +56,6 @@ void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue);
qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue);
qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue);
qScriptRegisterMetaType(engine, rayPickResultToScriptValue, rayPickResultFromScriptValue);
qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue);
qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue);
qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue);
@ -753,26 +751,6 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) {
}
}
QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult) {
QScriptValue obj = engine->newObject();
obj.setProperty("type", rayPickResult.type);
QScriptValue objectID = quuidToScriptValue(engine, rayPickResult.objectID);
obj.setProperty("objectID", objectID);
obj.setProperty("distance", rayPickResult.distance);
QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection);
obj.setProperty("intersection", intersection);
obj.setProperty("intersects", rayPickResult.type != NONE);
QScriptValue searchRay = pickRayToScriptValue(engine, rayPickResult.searchRay);
obj.setProperty("searchRay", searchRay);
QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal);
obj.setProperty("surfaceNormal", surfaceNormal);
return obj;
}
void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult) {
// TODO: cannot currently accept RayPickResults from JS
}
QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) {
QScriptValue obj = engine->newObject();
obj.setProperty("type", collision.type);

View file

@ -128,6 +128,7 @@ void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube);
class PickRay {
public:
PickRay() : origin(NAN), direction(NAN) { }
PickRay(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), direction(vec3FromVariant(pickVariant["direction"])) {}
PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {}
glm::vec3 origin;
glm::vec3 direction;
@ -138,6 +139,12 @@ public:
bool operator==(const PickRay& other) const {
return (origin == other.origin && direction == other.direction);
}
QVariantMap toVariantMap() const {
QVariantMap pickRay;
pickRay["origin"] = vec3toVariant(origin);
pickRay["direction"] = vec3toVariant(direction);
return pickRay;
}
};
namespace std {
template <>
@ -157,31 +164,6 @@ Q_DECLARE_METATYPE(PickRay)
QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay);
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);
enum IntersectionType {
NONE = 0,
ENTITY,
OVERLAY,
AVATAR,
HUD
};
class RayPickResult {
public:
RayPickResult() {}
RayPickResult(const PickRay& searchRay) : searchRay(searchRay) {}
RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) :
type(type), objectID(objectID), distance(distance), intersection(intersection), searchRay(searchRay), surfaceNormal(surfaceNormal) {}
IntersectionType type { NONE };
QUuid objectID;
float distance { FLT_MAX };
glm::vec3 intersection { NAN };
PickRay searchRay;
glm::vec3 surfaceNormal { NAN };
};
Q_DECLARE_METATYPE(RayPickResult)
QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult);
void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult);
enum ContactEventType {
CONTACT_EVENT_TYPE_START,
CONTACT_EVENT_TYPE_CONTINUE,