mirror of
https://github.com/lubosz/overte.git
synced 2025-04-10 20:43:39 +02:00
one global pickmanager
This commit is contained in:
parent
3572f7f5db
commit
d7745efc8e
14 changed files with 417 additions and 416 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "Application.h"
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
|
@ -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
|
||||
|
|
127
libraries/pointers/src/pointers/PickCacheOptimizer.h
Normal file
127
libraries/pointers/src/pointers/PickCacheOptimizer.h
Normal 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
|
94
libraries/pointers/src/pointers/PickManager.cpp
Normal file
94
libraries/pointers/src/pointers/PickManager.cpp
Normal 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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue