one global pickmanager

This commit is contained in:
SamGondelman 2017-10-19 16:55:24 -07:00
parent 3572f7f5db
commit d7745efc8e
14 changed files with 417 additions and 416 deletions

View file

@ -195,6 +195,7 @@
#include <raypick/RayPickScriptingInterface.h>
#include <raypick/LaserPointerScriptingInterface.h>
#include <raypick/MouseRayPick.h>
#include <FadeEffect.h>
@ -750,8 +751,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_notifiedPacketVersionMismatchThisDomain(false),
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
_lastFaceTrackerUpdate(0),
_snapshotSound(nullptr)
{
_snapshotSound(nullptr) {
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
@ -795,7 +795,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
installNativeEventFilter(&MyNativeEventFilter::getInstance());
#endif
_logger = new FileLogger(this);
qInstallMessageHandler(messageHandler);
@ -850,13 +850,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto audioIO = DependencyManager::get<AudioClient>();
audioIO->setPositionGetter([]{
audioIO->setPositionGetter([] {
auto avatarManager = DependencyManager::get<AvatarManager>();
auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr;
return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO;
});
audioIO->setOrientationGetter([]{
audioIO->setOrientationGetter([] {
auto avatarManager = DependencyManager::get<AvatarManager>();
auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr;
@ -867,7 +867,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
audioIO->handleRecordedAudioInput(frame->data);
});
connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){
connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio) {
static auto recorder = DependencyManager::get<recording::Recorder>();
if (recorder->isRecording()) {
static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName());
@ -956,14 +956,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto addressManager = DependencyManager::get<AddressManager>();
// use our MyAvatar position and quat for address manager path
addressManager->setPositionGetter([this]{ return getMyAvatar()->getPosition(); });
addressManager->setOrientationGetter([this]{ return getMyAvatar()->getOrientation(); });
addressManager->setPositionGetter([this] { return getMyAvatar()->getPosition(); });
addressManager->setOrientationGetter([this] { return getMyAvatar()->getOrientation(); });
connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
connect(this, &Application::activeDisplayPluginChanged, this, [](){
connect(this, &Application::activeDisplayPluginChanged, this, []() {
qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode());
});
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode);
@ -973,7 +973,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine) {
registerScriptEngineWithApplicationServices(engine);
});
@ -989,7 +989,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}, Qt::QueuedConnection);
connect(scriptEngines, &ScriptEngines::scriptLoadError,
scriptEngines, [](const QString& filename, const QString& error){
scriptEngines, [](const QString& filename, const QString& error) {
OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load.");
}, Qt::QueuedConnection);
@ -1101,7 +1101,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
// add firstRun flag from settings to launch event
Setting::Handle<bool> firstRun { Settings::firstRun, true };
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
// once the settings have been loaded, check if we need to flip the default for UserActivityLogger
auto& userActivityLogger = UserActivityLogger::getInstance();
@ -1202,42 +1202,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
static int lastKey = Qt::Key_unknown;
bool navAxis = false;
switch (actionEnum) {
case Action::UI_NAV_VERTICAL:
navAxis = true;
if (state > 0.0f) {
key = Qt::Key_Up;
} else if (state < 0.0f) {
key = Qt::Key_Down;
}
break;
case Action::UI_NAV_VERTICAL:
navAxis = true;
if (state > 0.0f) {
key = Qt::Key_Up;
} else if (state < 0.0f) {
key = Qt::Key_Down;
}
break;
case Action::UI_NAV_LATERAL:
navAxis = true;
if (state > 0.0f) {
key = Qt::Key_Right;
} else if (state < 0.0f) {
key = Qt::Key_Left;
}
break;
case Action::UI_NAV_LATERAL:
navAxis = true;
if (state > 0.0f) {
key = Qt::Key_Right;
} else if (state < 0.0f) {
key = Qt::Key_Left;
}
break;
case Action::UI_NAV_GROUP:
navAxis = true;
if (state > 0.0f) {
key = Qt::Key_Tab;
} else if (state < 0.0f) {
key = Qt::Key_Backtab;
}
break;
case Action::UI_NAV_GROUP:
navAxis = true;
if (state > 0.0f) {
key = Qt::Key_Tab;
} else if (state < 0.0f) {
key = Qt::Key_Backtab;
}
break;
case Action::UI_NAV_BACK:
key = Qt::Key_Escape;
break;
case Action::UI_NAV_BACK:
key = Qt::Key_Escape;
break;
case Action::UI_NAV_SELECT:
key = Qt::Key_Return;
break;
default:
break;
case Action::UI_NAV_SELECT:
key = Qt::Key_Return;
break;
default:
break;
}
auto window = tabletScriptingInterface->getTabletWindow();
@ -1376,8 +1376,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
QTimer* settingsTimer = new QTimer();
moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{
connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{
moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer] {
connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer] {
// Disconnect the signal from the save settings
QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
// Stop the settings timer
@ -1439,7 +1439,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Now that menu is initialized we can sync myAvatar with it's state.
myAvatar->updateMotionBehaviorFromMenu();
// FIXME spacemouse code still needs cleanup
// FIXME spacemouse code still needs cleanup
#if 0
// the 3Dconnexion device wants to be initialized after a window is displayed.
SpacemouseManager::getInstance().init();
@ -1448,7 +1448,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
[this](const EntityItemID& entityItemID, const PointerEvent& event) {
[this](const EntityItemID& entityItemID, const PointerEvent& event) {
if (getEntities()->wantsKeyboardFocus(entityItemID)) {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
setKeyboardFocusEntity(entityItemID);
@ -1663,8 +1663,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
totalServerOctreeElements += i->second.getTotalElements();
}
properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount();
properties["server_octree_elements"] = (qint64) totalServerOctreeElements;
properties["local_octree_elements"] = (qint64)OctreeElement::getInternalNodeCount();
properties["server_octree_elements"] = (qint64)totalServerOctreeElements;
properties["active_display_plugin"] = getActiveDisplayPlugin()->getName();
properties["using_hmd"] = isHMDMode();
@ -1685,7 +1685,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (_autoSwitchDisplayModeSupportedHMDPlugin) {
if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin &&
!_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
startHMDStandBySession();
startHMDStandBySession();
}
// Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly.
// If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode.
@ -1729,7 +1729,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() {
auto avatarManager = DependencyManager::get<AvatarManager>();
int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(),
NEARBY_AVATAR_RADIUS_METERS) - 1;
NEARBY_AVATAR_RADIUS_METERS) - 1;
if (nearbyAvatars != lastCountOfNearbyAvatars) {
lastCountOfNearbyAvatars = nearbyAvatars;
UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } });
@ -1817,14 +1817,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged);
_pickManager.setShouldPickHUDOperator([&]() { return DependencyManager::get<HMDScriptingInterface>()->isHMDMode(); });
// Setup the mouse ray pick and related operators
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickID(_rayPickManager.createRayPick(
PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()),
0.0f, true));
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickID(_pickManager.addPick(RAY, std::make_shared<MouseRayPick>(
PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true)));
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickResultOperator([&](QUuid rayPickID) {
RayToEntityIntersectionResult entityResult;
entityResult.intersects = false;
QVariantMap result = _rayPickManager.getPrevPickResult(rayPickID);
QVariantMap result = _pickManager.getPrevPickResult(rayPickID);
if (result["type"].isValid()) {
entityResult.intersects = result["type"] != RayPickScriptingInterface::INTERSECTED_NONE();
if (entityResult.intersects) {
@ -1838,7 +1839,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return entityResult;
});
DependencyManager::get<EntityTreeRenderer>()->setSetPrecisionPickingOperator([&](QUuid rayPickID, bool value) {
_rayPickManager.setPrecisionPicking(rayPickID, value);
_pickManager.setPrecisionPicking(rayPickID, value);
});
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
@ -4910,8 +4911,8 @@ void Application::update(float deltaTime) {
// TODO: break these out into distinct perfTimers when they prove interesting
{
PROFILE_RANGE(app, "RayPickManager");
_rayPickManager.update();
PROFILE_RANGE(app, "PickManager");
_pickManager.update();
}
{

View file

@ -70,7 +70,7 @@
#include "ui/overlays/Overlays.h"
#include "UndoStackScriptingInterface.h"
#include "raypick/RayPickManager.h"
#include <pointers/PickManager.h>
#include "raypick/LaserPointerManager.h"
#include <procedural/ProceduralSkybox.h>
@ -299,7 +299,7 @@ public:
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
LaserPointerManager& getLaserPointerManager() { return _laserPointerManager; }
RayPickManager& getRayPickManager() { return _rayPickManager; }
PickManager& getPickManager() { return _pickManager; }
signals:
void svoImportRequested(const QString& url);
@ -713,7 +713,7 @@ private:
bool _saveAvatarOverrideUrl { false };
QObject* _renderEventHandler{ nullptr };
RayPickManager _rayPickManager;
PickManager _pickManager;
LaserPointerManager _laserPointerManager;
friend class RenderEventHandler;

View file

@ -38,7 +38,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
}
LaserPointer::~LaserPointer() {
qApp->getRayPickManager().removePick(_rayPickUID);
qApp->getPickManager().removePick(_rayPickUID);
for (auto& renderState : _renderStates) {
renderState.second.deleteOverlays();
@ -49,14 +49,14 @@ LaserPointer::~LaserPointer() {
}
void LaserPointer::enable() {
qApp->getRayPickManager().enablePick(_rayPickUID);
qApp->getPickManager().enablePick(_rayPickUID);
withWriteLock([&] {
_renderingEnabled = true;
});
}
void LaserPointer::disable() {
qApp->getRayPickManager().disablePick(_rayPickUID);
qApp->getPickManager().disablePick(_rayPickUID);
withWriteLock([&] {
_renderingEnabled = false;
if (!_currentRenderState.empty()) {
@ -101,7 +101,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
}
const QVariantMap LaserPointer::getPrevRayPickResult() {
return qApp->getRayPickManager().getPrevPickResult(_rayPickUID);
return qApp->getPickManager().getPrevPickResult(_rayPickUID);
}
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
@ -197,7 +197,7 @@ 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([&] {
QVariantMap prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID);
QVariantMap prevRayPickResult = qApp->getPickManager().getPrevPickResult(_rayPickUID);
IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt());
PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap());
QUuid uid = prevRayPickResult["objectID"].toUuid();
@ -217,7 +217,7 @@ void LaserPointer::update() {
}
void LaserPointer::setPrecisionPicking(const bool precisionPicking) {
qApp->getRayPickManager().setPrecisionPicking(_rayPickUID, precisionPicking);
qApp->getPickManager().setPrecisionPicking(_rayPickUID, precisionPicking);
}
void LaserPointer::setLaserLength(const float laserLength) {
@ -233,11 +233,11 @@ void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) {
}
void LaserPointer::setIgnoreItems(const QVector<QUuid>& ignoreItems) const {
qApp->getRayPickManager().setIgnoreItems(_rayPickUID, ignoreItems);
qApp->getPickManager().setIgnoreItems(_rayPickUID, ignoreItems);
}
void LaserPointer::setIncludeItems(const QVector<QUuid>& includeItems) const {
qApp->getRayPickManager().setIncludeItems(_rayPickUID, includeItems);
qApp->getPickManager().setIncludeItems(_rayPickUID, includeItems);
}
RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) :

View file

@ -14,7 +14,6 @@
#include <QtCore/QVariant>
#include <GLMHelpers.h>
#include <RegisteredMetaTypes.h>
void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const {
qApp->getLaserPointerManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));

View file

@ -13,7 +13,6 @@
#include <QtCore/QObject>
#include "RegisteredMetaTypes.h"
#include "DependencyManager.h"
#include "Application.h"

View file

@ -1,24 +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 "RayPickManager.h"
#include "StaticRayPick.h"
#include "JointRayPick.h"
#include "MouseRayPick.h"
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) {
return addPick(std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled));
}
QUuid RayPickManager::createRayPick(const PickFilter& filter, float maxDistance, bool enabled) {
return addPick(std::make_shared<MouseRayPick>(filter, maxDistance, enabled));
}
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) {
return addPick(std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled));
}

View file

@ -1,22 +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
//
#ifndef hifi_RayPickManager_h
#define hifi_RayPickManager_h
#include <pointers/PickManager.h>
#include "RegisteredMetaTypes.h"
class RayPickManager : public PickManager<PickRay> {
public:
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

View file

@ -15,6 +15,10 @@
#include "GLMHelpers.h"
#include "Application.h"
#include "StaticRayPick.h"
#include "JointRayPick.h"
#include "MouseRayPick.h"
QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) {
QVariantMap propMap = properties.toMap();
@ -48,9 +52,10 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) {
dirOffset = vec3FromVariant(propMap["dirOffset"]);
}
return qApp->getRayPickManager().createRayPick(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
return qApp->getPickManager().addPick(RAY, std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled));
} else {
return qApp->getRayPickManager().createRayPick(filter, maxDistance, enabled);
return qApp->getPickManager().addPick(RAY, std::make_shared<MouseRayPick>(filter, maxDistance, enabled));
}
} else if (propMap["position"].isValid()) {
glm::vec3 position = vec3FromVariant(propMap["position"]);
@ -60,36 +65,36 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) {
direction = vec3FromVariant(propMap["direction"]);
}
return qApp->getRayPickManager().createRayPick(position, direction, filter, maxDistance, enabled);
return qApp->getPickManager().addPick(RAY, std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled));
}
return QUuid();
}
void RayPickScriptingInterface::enableRayPick(const QUuid& uid) {
qApp->getRayPickManager().enablePick(uid);
qApp->getPickManager().enablePick(uid);
}
void RayPickScriptingInterface::disableRayPick(const QUuid& uid) {
qApp->getRayPickManager().disablePick(uid);
qApp->getPickManager().disablePick(uid);
}
void RayPickScriptingInterface::removeRayPick(const QUuid& uid) {
qApp->getRayPickManager().removePick(uid);
qApp->getPickManager().removePick(uid);
}
QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) {
return qApp->getRayPickManager().getPrevPickResult(uid);
return qApp->getPickManager().getPrevPickResult(uid);
}
void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) {
qApp->getRayPickManager().setPrecisionPicking(uid, precisionPicking);
qApp->getPickManager().setPrecisionPicking(uid, precisionPicking);
}
void RayPickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) {
qApp->getRayPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
qApp->getPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void RayPickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) {
qApp->getRayPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
qApp->getPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}

View file

@ -7,4 +7,74 @@
//
#include "Pick.h"
const PickFilter PickFilter::NOTHING;
const PickFilter PickFilter::NOTHING;
PickQuery::PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled) {
}
void PickQuery::enable(bool enabled) {
withWriteLock([&] {
_enabled = enabled;
});
}
PickFilter PickQuery::getFilter() const {
return resultWithReadLock<PickFilter>([&] {
return _filter;
});
}
float PickQuery::getMaxDistance() const {
return _maxDistance;
}
bool PickQuery::isEnabled() const {
return resultWithReadLock<bool>([&] {
return _enabled;
});
}
void PickQuery::setPrecisionPicking(bool precisionPicking) {
withWriteLock([&] {
_filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking);
});
}
void PickQuery::setPickResult(const PickResultPointer& pickResult) {
withWriteLock([&] {
_prevResult = pickResult;
});
}
QVector<QUuid> PickQuery::getIgnoreItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _ignoreItems;
});
}
QVector<QUuid> PickQuery::getIncludeItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _includeItems;
});
}
PickResultPointer PickQuery::getPrevPickResult() const {
return resultWithReadLock<PickResultPointer>([&] {
return _prevResult;
});
}
void PickQuery::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
withWriteLock([&] {
_ignoreItems = ignoreItems;
});
}
void PickQuery::setIncludeItems(const QVector<QUuid>& includeItems) {
withWriteLock([&] {
_includeItems = includeItems;
});
}

View file

@ -129,18 +129,9 @@ public:
using PickResultPointer = std::shared_ptr<PickResult>;
template<typename T>
class Pick : protected ReadWriteLockable {
class PickQuery : protected ReadWriteLockable {
public:
Pick(const PickFilter& filter, const float maxDistance, const bool enabled);
virtual const T getMathematicalPick() const = 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;
PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled);
void enable(bool enabled = true);
void disable() { enable(false); }
@ -193,85 +184,16 @@ private:
};
template<typename T>
Pick<T>::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled) {
}
class Pick : public PickQuery {
public:
Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, 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 {
return resultWithReadLock<bool>([&] {
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 PickResultPointer& pickResult) {
withWriteLock([&] {
_prevResult = pickResult;
});
}
template<typename T>
QVector<QUuid> Pick<T>::getIgnoreItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _ignoreItems;
});
}
template<typename T>
QVector<QUuid> Pick<T>::getIncludeItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _includeItems;
});
}
template<typename T>
PickResultPointer Pick<T>::getPrevPickResult() const {
return resultWithReadLock<PickResultPointer>([&] {
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;
});
}
virtual const T getMathematicalPick() const = 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;
};
#endif // hifi_Pick_h

View file

@ -0,0 +1,127 @@
//
// 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_PickCacheOptimizer_h
#define hifi_PickCacheOptimizer_h
#include <unordered_map>
#include "Pick.h"
typedef struct PickCacheKey {
PickFilter::Flags mask;
QVector<QUuid> include;
QVector<QUuid> ignore;
bool operator==(const PickCacheKey& other) const {
return (mask == other.mask && include == other.include && ignore == other.ignore);
}
} PickCacheKey;
namespace std {
template <>
struct hash<PickCacheKey> {
size_t operator()(const PickCacheKey& 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 (a MathPick)
// For example: RayPicks use T = PickRay
template<typename T>
class PickCacheOptimizer {
public:
void update(QHash<QUuid, std::shared_ptr<PickQuery>>& picks, bool shouldPickHUD);
protected:
typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
// 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>
bool PickCacheOptimizer<T>::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key) {
if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) {
res = res->compareAndProcessNewResult(cache[pick][key]);
return true;
}
return false;
}
template<typename T>
void PickCacheOptimizer<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[mathPick][key] = resTemp;
res = res->compareAndProcessNewResult(resTemp);
} else {
cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap());
}
}
template<typename T>
void PickCacheOptimizer<T>::update(QHash<QUuid, std::shared_ptr<PickQuery>>& picks, bool shouldPickHUD) {
PickCache results;
for (const auto& uid : picks.keys()) {
std::shared_ptr<Pick<T>> pick = std::static_pointer_cast<Pick<T>>(picks[uid]);
if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) {
continue;
}
T mathematicalPick = pick->getMathematicalPick();
if (!mathematicalPick) {
continue;
}
PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap());
if (pick->getFilter().doesPickEntities()) {
PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick);
cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick);
}
}
if (pick->getFilter().doesPickOverlays()) {
PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) {
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)) {
PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick);
cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick);
}
}
// Can't intersect with HUD in desktop mode
if (pick->getFilter().doesPickHUD() && shouldPickHUD) {
PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick);
cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick);
}
}
if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) {
pick->setPickResult(res);
} else {
pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap()));
}
}
}
#endif // hifi_PickCacheOptimizer_h

View file

@ -0,0 +1,94 @@
//
// Created by Sam Gondelman 10/19/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 "PickManager.h"
PickManager::PickManager() {
setShouldPickHUDOperator([]() { return false; });
}
QUuid PickManager::addPick(PickType type, const std::shared_ptr<PickQuery> pick) {
QUuid id = QUuid::createUuid();
withWriteLock([&] {
_picks[type][id] = pick;
_typeMap[id] = type;
});
return id;
}
std::shared_ptr<PickQuery> PickManager::findPick(const QUuid& uid) const {
return resultWithReadLock<std::shared_ptr<PickQuery>>([&] {
auto type = _typeMap.find(uid);
if (type != _typeMap.end()) {
return _picks[type.value()][uid];
}
return std::shared_ptr<PickQuery>();
});
}
void PickManager::removePick(const QUuid& uid) {
withWriteLock([&] {
auto type = _typeMap.find(uid);
if (type != _typeMap.end()) {
_picks[type.value()].remove(uid);
_typeMap.remove(uid);
}
});
}
QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const {
auto pick = findPick(uid);
if (pick && pick->getPrevPickResult()) {
return pick->getPrevPickResult()->toVariantMap();
}
return QVariantMap();
}
void PickManager::enablePick(const QUuid& uid) const {
auto pick = findPick(uid);
if (pick) {
pick->enable();
}
}
void PickManager::disablePick(const QUuid& uid) const {
auto pick = findPick(uid);
if (pick) {
pick->disable();
}
}
void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto pick = findPick(uid);
if (pick) {
pick->setPrecisionPicking(precisionPicking);
}
}
void PickManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
auto pick = findPick(uid);
if (pick) {
pick->setIgnoreItems(ignore);
}
}
void PickManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
auto pick = findPick(uid);
if (pick) {
pick->setIncludeItems(include);
}
}
void PickManager::update() {
QHash<PickType, QHash<QUuid, std::shared_ptr<PickQuery>>> cachedPicks;
withReadLock([&] {
cachedPicks = _picks;
});
bool shouldPickHUD = _shouldPickHUDOperator();
_rayPickCacheOptimizer.update(cachedPicks[RAY], shouldPickHUD);
}

View file

@ -10,220 +10,44 @@
#include <unordered_map>
#include "scripting/HMDScriptingInterface.h"
#include "RegisteredMetaTypes.h"
#include "Pick.h"
#include "PickCacheOptimizer.h"
typedef struct PickCacheKey {
PickFilter::Flags mask;
QVector<QUuid> include;
QVector<QUuid> ignore;
enum PickType {
RAY = 0,
STYLUS
};
bool operator==(const PickCacheKey& other) const {
return (mask == other.mask && include == other.include && ignore == other.ignore);
}
} PickCacheKey;
namespace std {
template <>
struct hash<PickCacheKey> {
size_t operator()(const PickCacheKey& 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: 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();
PickManager();
QVariantMap getPrevPickResult(const QUuid& uid) const;
void update();
QUuid addPick(const std::shared_ptr<Pick<T>> pick);
QUuid addPick(PickType type, const std::shared_ptr<PickQuery> pick);
void removePick(const QUuid& uid);
void enablePick(const QUuid& uid) const;
void disablePick(const QUuid& uid) const;
QVariantMap getPrevPickResult(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;
void setShouldPickHUDOperator(std::function<bool()> shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; }
protected:
std::shared_ptr<Pick<T>> findPick(const QUuid& uid) const;
QHash<QUuid, std::shared_ptr<Pick<T>>> _picks;
std::function<bool()> _shouldPickHUDOperator;
typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
std::shared_ptr<PickQuery> findPick(const QUuid& uid) const;
QHash<PickType, QHash<QUuid, std::shared_ptr<PickQuery>>> _picks;
QHash<QUuid, PickType> _typeMap;
// 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);
PickCacheOptimizer<PickRay> _rayPickCacheOptimizer;
};
template<typename T>
std::shared_ptr<Pick<T>> PickManager<T>::findPick(const QUuid& uid) const {
return resultWithReadLock<std::shared_ptr<Pick<T>>>([&] {
if (_picks.contains(uid)) {
return _picks[uid];
}
return std::shared_ptr<Pick<T>>();
});
}
template<typename T>
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()) {
res = res->compareAndProcessNewResult(cache[pick][key]);
return true;
}
return false;
}
template<typename T>
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[mathPick][key] = resTemp;
res = res->compareAndProcessNewResult(resTemp);
} else {
cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap());
}
}
template<typename T>
void PickManager<T>::update() {
PickCache results;
QHash<QUuid, std::shared_ptr<Pick<T>>> cachedPicks;
withReadLock([&] {
cachedPicks = _picks;
});
for (const auto& uid : cachedPicks.keys()) {
std::shared_ptr<Pick<T>> pick = cachedPicks[uid];
if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) {
continue;
}
T mathematicalPick = pick->getMathematicalPick();
if (!mathematicalPick) {
continue;
}
PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap());
if (pick->getFilter().doesPickEntities()) {
PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick);
cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick);
}
}
if (pick->getFilter().doesPickOverlays()) {
PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) {
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)) {
PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick);
cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick);
}
}
// Can't intersect with HUD in desktop mode
if (pick->getFilter().doesPickHUD() && DependencyManager::get<HMDScriptingInterface>()->isHMDMode()) {
PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick);
cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick);
}
}
if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) {
pick->setPickResult(res);
} else {
pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap()));
}
}
}
template<typename T>
QVariantMap PickManager<T>::getPrevPickResult(const QUuid& uid) const {
auto pick = findPick(uid);
if (pick && pick->getPrevPickResult()) {
return pick->getPrevPickResult()->toVariantMap();
}
return QVariantMap();
}
template<typename T>
QUuid PickManager<T>::addPick(const std::shared_ptr<Pick<T>> pick) {
QUuid id = QUuid::createUuid();
withWriteLock([&] {
_picks[id] = pick;
});
return id;
}
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 pick = findPick(uid);
if (pick) {
pick->enable();
}
}
template<typename T>
void PickManager<T>::disablePick(const QUuid& uid) const {
auto pick = findPick(uid);
if (pick) {
pick->disable();
}
}
template<typename T>
void PickManager<T>::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto pick = findPick(uid);
if (pick) {
pick->setPrecisionPicking(precisionPicking);
}
}
template<typename T>
void PickManager<T>::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
auto pick = findPick(uid);
if (pick) {
pick->setIgnoreItems(ignore);
}
}
template<typename T>
void PickManager<T>::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
auto pick = findPick(uid);
if (pick) {
pick->setIncludeItems(include);
}
}
#endif // hifi_PickManager_h

View file

@ -125,7 +125,13 @@ QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array);
QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube);
void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube);
class PickRay {
// MathPicks also have to overide operator== for their type
class MathPick {
virtual operator bool() const = 0;
virtual QVariantMap toVariantMap() const = 0;
};
class PickRay : public MathPick {
public:
PickRay() : origin(NAN), direction(NAN) { }
PickRay(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), direction(vec3FromVariant(pickVariant["direction"])) {}
@ -133,13 +139,13 @@ public:
glm::vec3 origin;
glm::vec3 direction;
operator bool() const {
operator bool() const override {
return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(direction)));
}
bool operator==(const PickRay& other) const {
return (origin == other.origin && direction == other.direction);
}
QVariantMap toVariantMap() const {
QVariantMap toVariantMap() const override {
QVariantMap pickRay;
pickRay["origin"] = vec3toVariant(origin);
pickRay["direction"] = vec3toVariant(direction);