merge from master

This commit is contained in:
SamGondelman 2017-10-26 12:14:53 -07:00
commit a44e8efb99
46 changed files with 1311 additions and 967 deletions

View file

@ -194,8 +194,13 @@
#include <EntityScriptClient.h>
#include <ModelScriptingInterface.h>
#include <pointers/PickManager.h>
#include <pointers/PointerManager.h>
#include <raypick/RayPickScriptingInterface.h>
#include <raypick/LaserPointerScriptingInterface.h>
#include <raypick/PickScriptingInterface.h>
#include <raypick/PointerScriptingInterface.h>
#include <raypick/MouseRayPick.h>
#include <FadeEffect.h>
@ -698,8 +703,12 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<FadeEffect>();
DependencyManager::set<PickManager>();
DependencyManager::set<PointerManager>();
DependencyManager::set<LaserPointerScriptingInterface>();
DependencyManager::set<RayPickScriptingInterface>();
DependencyManager::set<PointerScriptingInterface>();
DependencyManager::set<PickScriptingInterface>();
return previousSessionCrashed;
}
@ -1800,25 +1809,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged);
DependencyManager::get<PickManager>()->setShouldPickHUDOperator([&]() { return DependencyManager::get<HMDScriptingInterface>()->isHMDMode(); });
// Setup the mouse ray pick and related operators
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickID(_rayPickManager.createRayPick(
RayPickFilter(DependencyManager::get<RayPickScriptingInterface>()->PICK_ENTITIES() | DependencyManager::get<RayPickScriptingInterface>()->PICK_INCLUDE_NONCOLLIDABLE()),
0.0f, true));
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickID(DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, std::make_shared<MouseRayPick>(
PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true)));
DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickResultOperator([&](QUuid rayPickID) {
RayToEntityIntersectionResult entityResult;
RayPickResult result = _rayPickManager.getPrevRayPickResult(rayPickID);
entityResult.intersects = result.type != DependencyManager::get<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 = DependencyManager::get<PickManager>()->getPrevPickResult(rayPickID);
if (result["type"].isValid()) {
entityResult.intersects = result["type"] != PickScriptingInterface::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;
});
DependencyManager::get<EntityTreeRenderer>()->setSetPrecisionPickingOperator([&](QUuid rayPickID, bool value) {
_rayPickManager.setPrecisionPicking(rayPickID, value);
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
});
// Preload Tablet sounds
@ -4936,13 +4949,13 @@ 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");
DependencyManager::get<PickManager>()->update();
}
{
PROFILE_RANGE(app, "LaserPointerManager");
_laserPointerManager.update();
PROFILE_RANGE(app, "PointerManager");
DependencyManager::get<PointerManager>()->update();
}
{
@ -5821,6 +5834,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("RayPick", DependencyManager::get<RayPickScriptingInterface>().data());
scriptEngine->registerGlobalObject("LaserPointers", DependencyManager::get<LaserPointerScriptingInterface>().data());
scriptEngine->registerGlobalObject("Picks", DependencyManager::get<PickScriptingInterface>().data());
scriptEngine->registerGlobalObject("Pointers", DependencyManager::get<PointerScriptingInterface>().data());
// Caches
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());

View file

@ -70,9 +70,6 @@
#include "ui/overlays/Overlays.h"
#include "UndoStackScriptingInterface.h"
#include "raypick/RayPickManager.h"
#include "raypick/LaserPointerManager.h"
#include <procedural/ProceduralSkybox.h>
#include <model/Skybox.h>
#include <ModelScriptingInterface.h>
@ -286,9 +283,6 @@ public:
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
LaserPointerManager& getLaserPointerManager() { return _laserPointerManager; }
RayPickManager& getRayPickManager() { return _rayPickManager; }
signals:
void svoImportRequested(const QString& url);
@ -702,9 +696,6 @@ private:
bool _saveAvatarOverrideUrl { false };
QObject* _renderEventHandler{ nullptr };
RayPickManager _rayPickManager;
LaserPointerManager _laserPointerManager;
friend class RenderEventHandler;
std::atomic<bool> _pendingIdleEvent { false };

View file

@ -12,7 +12,7 @@
#include "avatar/AvatarManager.h"
JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) :
JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled) :
RayPick(filter, maxDistance, enabled),
_jointName(jointName),
_posOffset(posOffset),
@ -20,7 +20,7 @@ JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOff
{
}
const PickRay JointRayPick::getPickRay(bool& valid) const {
const PickRay JointRayPick::getMathematicalPick() const {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName));
bool useAvatarHead = _jointName == "Avatar";
@ -38,10 +38,8 @@ const PickRay JointRayPick::getPickRay(bool& valid) const {
pos = pos + (rot * (myAvatar->getSensorToWorldScale() * _posOffset));
glm::vec3 dir = rot * glm::normalize(_dirOffset);
valid = true;
return PickRay(pos, dir);
}
valid = false;
return PickRay();
}

View file

@ -11,14 +11,14 @@
#ifndef hifi_JointRayPick_h
#define hifi_JointRayPick_h
#include <pointers/rays/RayPick.h>
#include "RayPick.h"
class JointRayPick : public RayPick {
public:
JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getPickRay(bool& valid) const override;
const PickRay getMathematicalPick() const override;
private:
std::string _jointName;

View file

@ -12,21 +12,22 @@
#include "Application.h"
#include "avatar/AvatarManager.h"
#include "RayPickScriptingInterface.h"
#include <DependencyManager.h>
#include <pointers/PickManager.h>
#include "PickScriptingInterface.h"
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) :
Pointer(DependencyManager::get<PickScriptingInterface>()->createRayPick(rayProps)),
_renderingEnabled(enabled),
_renderStates(renderStates),
_defaultRenderStates(defaultRenderStates),
_faceAvatar(faceAvatar),
_centerEndY(centerEndY),
_lockEnd(lockEnd),
_distanceScaleEnd(distanceScaleEnd),
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps))
_distanceScaleEnd(distanceScaleEnd)
{
for (auto& state : _renderStates) {
if (!enabled || state.first != _currentRenderState) {
disableRenderState(state.second);
@ -40,8 +41,6 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
}
LaserPointer::~LaserPointer() {
qApp->getRayPickManager().removeRayPick(_rayPickUID);
for (auto& renderState : _renderStates) {
renderState.second.deleteOverlays();
}
@ -51,14 +50,14 @@ LaserPointer::~LaserPointer() {
}
void LaserPointer::enable() {
qApp->getRayPickManager().enableRayPick(_rayPickUID);
Pointer::enable();
withWriteLock([&] {
_renderingEnabled = true;
});
}
void LaserPointer::disable() {
qApp->getRayPickManager().disableRayPick(_rayPickUID);
Pointer::disable();
withWriteLock([&] {
_renderingEnabled = false;
if (!_currentRenderState.empty()) {
@ -106,10 +105,6 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
}
}
const RayPickResult LaserPointer::getPrevRayPickResult() {
return qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID);
}
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
if (!renderState.getStartID().isNull()) {
QVariantMap startProps;
@ -207,15 +202,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().getPrevRayPickResult(_rayPickUID);
QVariantMap prevRayPickResult = DependencyManager::get<PickManager>()->getPrevPickResult(_pickUID);
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);
@ -223,13 +221,9 @@ void LaserPointer::update() {
});
}
void LaserPointer::setPrecisionPicking(const bool precisionPicking) {
qApp->getRayPickManager().setPrecisionPicking(_rayPickUID, precisionPicking);
}
void LaserPointer::setLaserLength(const float laserLength) {
void LaserPointer::setLength(const float length) {
withWriteLock([&] {
_laserLength = laserLength;
_laserLength = length;
});
}
@ -239,14 +233,6 @@ void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) {
});
}
void LaserPointer::setIgnoreItems(const QVector<QUuid>& ignoreItems) const {
qApp->getRayPickManager().setIgnoreItems(_rayPickUID, ignoreItems);
}
void LaserPointer::setIncludeItems(const QVector<QUuid>& includeItems) const {
qApp->getRayPickManager().setIncludeItems(_rayPickUID, includeItems);
}
RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) :
_startID(startID), _pathID(pathID), _endID(endID)
{
@ -273,3 +259,35 @@ void RenderState::deleteOverlays() {
qApp->getOverlays().deleteOverlay(_endID);
}
}
RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) {
QUuid startID;
if (propMap["start"].isValid()) {
QVariantMap startMap = propMap["start"].toMap();
if (startMap["type"].isValid()) {
startMap.remove("visible");
startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap);
}
}
QUuid pathID;
if (propMap["path"].isValid()) {
QVariantMap pathMap = propMap["path"].toMap();
// right now paths must be line3ds
if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") {
pathMap.remove("visible");
pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap);
}
}
QUuid endID;
if (propMap["end"].isValid()) {
QVariantMap endMap = propMap["end"].toMap();
if (endMap["type"].isValid()) {
endMap.remove("visible");
endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap);
}
}
return RenderState(startID, pathID, endID);
}

View file

@ -14,12 +14,10 @@
#include <QString>
#include <glm/glm.hpp>
#include <DependencyManager.h>
#include <shared/ReadWriteLockable.h>
#include "ui/overlays/Overlay.h"
class RayPickResult;
#include <pointers/Pointer.h>
#include <pointers/Pick.h>
class RenderState {
@ -50,12 +48,9 @@ private:
glm::vec3 _endDim;
};
class LaserPointer : public ReadWriteLockable {
class LaserPointer : public Pointer {
public:
using Pointer = std::shared_ptr<LaserPointer>;
typedef std::unordered_map<std::string, RenderState> RenderStateMap;
typedef std::unordered_map<std::string, std::pair<float, RenderState>> DefaultRenderStateMap;
@ -63,23 +58,19 @@ public:
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
~LaserPointer();
QUuid getRayUID() { return _rayPickUID; }
void enable();
void disable();
const RayPickResult getPrevRayPickResult();
void enable() override;
void disable() override;
void setRenderState(const std::string& state);
void setRenderState(const std::string& state) override;
// 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.
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override;
void setPrecisionPicking(const bool precisionPicking);
void setLaserLength(const float laserLength);
void setLockEndUUID(QUuid objectID, const bool isOverlay);
void setLength(const float length) override;
void setLockEndUUID(QUuid objectID, const bool isOverlay) override;
void setIgnoreItems(const QVector<QUuid>& ignoreItems) const;
void setIncludeItems(const QVector<QUuid>& includeItems) const;
void update() override;
void update();
static RenderState buildRenderState(const QVariantMap& propMap);
private:
bool _renderingEnabled;
@ -93,8 +84,6 @@ private:
bool _distanceScaleEnd;
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
const QUuid _rayPickUID;
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState);
void disableRenderState(const RenderState& renderState);

View file

@ -1,121 +0,0 @@
//
// LaserPointerManager.cpp
// interface/src/raypick
//
// 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 "LaserPointerManager.h"
QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) {
QUuid result;
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
if (!laserPointer->getRayUID().isNull()) {
result = QUuid::createUuid();
withWriteLock([&] { _laserPointers[result] = laserPointer; });
}
return result;
}
LaserPointer::Pointer LaserPointerManager::find(const QUuid& uid) const {
return resultWithReadLock<LaserPointer::Pointer>([&] {
auto itr = _laserPointers.find(uid);
if (itr != _laserPointers.end()) {
return *itr;
}
return LaserPointer::Pointer();
});
}
void LaserPointerManager::removeLaserPointer(const QUuid& uid) {
withWriteLock([&] {
_laserPointers.remove(uid);
});
}
void LaserPointerManager::enableLaserPointer(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->enable();
}
}
void LaserPointerManager::disableLaserPointer(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->disable();
}
}
void LaserPointerManager::setRenderState(const QUuid& uid, const std::string& renderState) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setRenderState(renderState);
}
}
void LaserPointerManager::editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->editRenderState(state, startProps, pathProps, endProps);
}
}
const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
return laserPointer->getPrevRayPickResult();
}
return RayPickResult();
}
void LaserPointerManager::update() {
auto cachedLaserPointers = resultWithReadLock<QList<std::shared_ptr<LaserPointer>>>([&] {
return _laserPointers.values();
});
for (const auto& laserPointer : cachedLaserPointers) {
laserPointer->update();
}
}
void LaserPointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setPrecisionPicking(precisionPicking);
}
}
void LaserPointerManager::setLaserLength(const QUuid& uid, const float laserLength) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setLaserLength(laserLength);
}
}
void LaserPointerManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setIgnoreItems(ignoreEntities);
}
}
void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setIncludeItems(includeEntities);
}
}
void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setLockEndUUID(objectID, isOverlay);
}
}

View file

@ -1,51 +0,0 @@
//
// LaserPointerManager.h
// interface/src/raypick
//
// 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_LaserPointerManager_h
#define hifi_LaserPointerManager_h
#include <memory>
#include <glm/glm.hpp>
#include <shared/ReadWriteLockable.h>
#include "LaserPointer.h"
class RayPickResult;
class LaserPointerManager : protected ReadWriteLockable {
public:
QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
void removeLaserPointer(const QUuid& uid);
void enableLaserPointer(const QUuid& uid) const;
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;
void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const;
void setLaserLength(const QUuid& uid, const float laserLength) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const;
void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const;
void update();
private:
LaserPointer::Pointer find(const QUuid& uid) const;
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
};
#endif // hifi_LaserPointerManager_h

View file

@ -11,127 +11,20 @@
#include "LaserPointerScriptingInterface.h"
#include <QtCore/QVariant>
#include <GLMHelpers.h>
#include <RegisteredMetaTypes.h>
#include "RegisteredMetaTypes.h"
#include "PointerScriptingInterface.h"
void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const {
qApp->getLaserPointerManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
DependencyManager::get<PointerManager>()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void LaserPointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const {
qApp->getLaserPointerManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
DependencyManager::get<PointerManager>()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}
QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) const {
QVariantMap propertyMap = properties.toMap();
bool faceAvatar = false;
if (propertyMap["faceAvatar"].isValid()) {
faceAvatar = propertyMap["faceAvatar"].toBool();
}
bool centerEndY = true;
if (propertyMap["centerEndY"].isValid()) {
centerEndY = propertyMap["centerEndY"].toBool();
}
bool lockEnd = false;
if (propertyMap["lockEnd"].isValid()) {
lockEnd = propertyMap["lockEnd"].toBool();
}
bool distanceScaleEnd = false;
if (propertyMap["distanceScaleEnd"].isValid()) {
distanceScaleEnd = propertyMap["distanceScaleEnd"].toBool();
}
bool enabled = false;
if (propertyMap["enabled"].isValid()) {
enabled = propertyMap["enabled"].toBool();
}
LaserPointer::RenderStateMap renderStates;
if (propertyMap["renderStates"].isValid()) {
QList<QVariant> renderStateVariants = propertyMap["renderStates"].toList();
for (QVariant& renderStateVariant : renderStateVariants) {
if (renderStateVariant.isValid()) {
QVariantMap renderStateMap = renderStateVariant.toMap();
if (renderStateMap["name"].isValid()) {
std::string name = renderStateMap["name"].toString().toStdString();
renderStates[name] = buildRenderState(renderStateMap);
}
}
}
}
LaserPointer::DefaultRenderStateMap defaultRenderStates;
if (propertyMap["defaultRenderStates"].isValid()) {
QList<QVariant> renderStateVariants = propertyMap["defaultRenderStates"].toList();
for (QVariant& renderStateVariant : renderStateVariants) {
if (renderStateVariant.isValid()) {
QVariantMap renderStateMap = renderStateVariant.toMap();
if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) {
std::string name = renderStateMap["name"].toString().toStdString();
float distance = renderStateMap["distance"].toFloat();
defaultRenderStates[name] = std::pair<float, RenderState>(distance, buildRenderState(renderStateMap));
}
}
}
}
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
return DependencyManager::get<PointerScriptingInterface>()->createLaserPointer(properties);
}
void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const {
QVariantMap propMap = properties.toMap();
QVariant startProps;
if (propMap["start"].isValid()) {
startProps = propMap["start"];
}
QVariant pathProps;
if (propMap["path"].isValid()) {
pathProps = propMap["path"];
}
QVariant endProps;
if (propMap["end"].isValid()) {
endProps = propMap["end"];
}
qApp->getLaserPointerManager().editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps);
}
RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) {
QUuid startID;
if (propMap["start"].isValid()) {
QVariantMap startMap = propMap["start"].toMap();
if (startMap["type"].isValid()) {
startMap.remove("visible");
startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap);
}
}
QUuid pathID;
if (propMap["path"].isValid()) {
QVariantMap pathMap = propMap["path"].toMap();
// right now paths must be line3ds
if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") {
pathMap.remove("visible");
pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap);
}
}
QUuid endID;
if (propMap["end"].isValid()) {
QVariantMap endMap = propMap["end"].toMap();
if (endMap["type"].isValid()) {
endMap.remove("visible");
endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap);
}
}
return RenderState(startID, pathID, endID);
DependencyManager::get<PointerScriptingInterface>()->editRenderState(uid, renderState, properties);
}

View file

@ -13,9 +13,8 @@
#include <QtCore/QObject>
#include "RegisteredMetaTypes.h"
#include "DependencyManager.h"
#include "Application.h"
#include <pointers/PointerManager.h>
class LaserPointerScriptingInterface : public QObject, public Dependency {
Q_OBJECT
@ -23,22 +22,19 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
public slots:
Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties) const;
Q_INVOKABLE void enableLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().enableLaserPointer(uid); }
Q_INVOKABLE void disableLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().disableLaserPointer(uid); }
Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().removeLaserPointer(uid); }
Q_INVOKABLE void enableLaserPointer(const QUuid& uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); }
Q_INVOKABLE void disableLaserPointer(const QUuid& uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); }
Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { DependencyManager::get<PointerManager>()->removePointer(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 void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get<PointerManager>()->setRenderState(uid, renderState.toStdString()); }
Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return DependencyManager::get<PointerManager>()->getPrevPickResult(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); }
Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get<PointerManager>()->setPrecisionPicking(uid, precisionPicking); }
Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get<PointerManager>()->setLength(uid, laserLength); }
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const;
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const;
Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); }
private:
static RenderState buildRenderState(const QVariantMap& propMap);
Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay); }
};

View file

@ -10,23 +10,20 @@
//
#include "MouseRayPick.h"
#include "DependencyManager.h"
#include "Application.h"
#include "display-plugins/CompositorHelper.h"
MouseRayPick::MouseRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) :
MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, const bool enabled) :
RayPick(filter, maxDistance, enabled)
{
}
const PickRay MouseRayPick::getPickRay(bool& valid) const {
const PickRay MouseRayPick::getMathematicalPick() const {
QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition();
if (position.isValid()) {
QVariantMap posMap = position.toMap();
valid = true;
return qApp->getCamera().computePickRay(posMap["x"].toFloat(), posMap["y"].toFloat());
}
valid = false;
return PickRay();
}

View file

@ -11,14 +11,14 @@
#ifndef hifi_MouseRayPick_h
#define hifi_MouseRayPick_h
#include <pointers/rays/RayPick.h>
#include "RayPick.h"
class MouseRayPick : public RayPick {
public:
MouseRayPick(const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getPickRay(bool& valid) const override;
const PickRay getMathematicalPick() const override;
};
#endif // hifi_MouseRayPick_h

View file

@ -0,0 +1,107 @@
//
// Created by Sam Gondelman 10/20/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 "PickScriptingInterface.h"
#include <QVariant>
#include "GLMHelpers.h"
#include <pointers/PickManager.h>
#include "StaticRayPick.h"
#include "JointRayPick.h"
#include "MouseRayPick.h"
QUuid PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) {
switch (type) {
case PickQuery::PickType::Ray:
return createRayPick(properties);
default:
return QUuid();
}
}
QUuid PickScriptingInterface::createRayPick(const QVariant& properties) {
QVariantMap propMap = properties.toMap();
bool enabled = false;
if (propMap["enabled"].isValid()) {
enabled = propMap["enabled"].toBool();
}
PickFilter filter = PickFilter();
if (propMap["filter"].isValid()) {
filter = PickFilter(propMap["filter"].toUInt());
}
float maxDistance = 0.0f;
if (propMap["maxDistance"].isValid()) {
maxDistance = propMap["maxDistance"].toFloat();
}
if (propMap["joint"].isValid()) {
std::string jointName = propMap["joint"].toString().toStdString();
if (jointName != "Mouse") {
// x = upward, y = forward, z = lateral
glm::vec3 posOffset = Vectors::ZERO;
if (propMap["posOffset"].isValid()) {
posOffset = vec3FromVariant(propMap["posOffset"]);
}
glm::vec3 dirOffset = Vectors::UP;
if (propMap["dirOffset"].isValid()) {
dirOffset = vec3FromVariant(propMap["dirOffset"]);
}
return DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled));
} else {
return DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, std::make_shared<MouseRayPick>(filter, maxDistance, enabled));
}
} else if (propMap["position"].isValid()) {
glm::vec3 position = vec3FromVariant(propMap["position"]);
glm::vec3 direction = -Vectors::UP;
if (propMap["direction"].isValid()) {
direction = vec3FromVariant(propMap["direction"]);
}
return DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled));
}
return QUuid();
}
void PickScriptingInterface::enablePick(const QUuid& uid) {
DependencyManager::get<PickManager>()->enablePick(uid);
}
void PickScriptingInterface::disablePick(const QUuid& uid) {
DependencyManager::get<PickManager>()->disablePick(uid);
}
void PickScriptingInterface::removePick(const QUuid& uid) {
DependencyManager::get<PickManager>()->removePick(uid);
}
QVariantMap PickScriptingInterface::getPrevPickResult(const QUuid& uid) {
return DependencyManager::get<PickManager>()->getPrevPickResult(uid);
}
void PickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) {
DependencyManager::get<PickManager>()->setPrecisionPicking(uid, precisionPicking);
}
void PickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) {
DependencyManager::get<PickManager>()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void PickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) {
DependencyManager::get<PickManager>()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}

View file

@ -0,0 +1,65 @@
//
// Created by Sam Gondelman 10/20/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_PickScriptingInterface_h
#define hifi_PickScriptingInterface_h
#include <QtCore/QObject>
#include <RegisteredMetaTypes.h>
#include <DependencyManager.h>
#include <pointers/Pick.h>
class PickScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT)
Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT)
Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT)
Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT)
Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT)
Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT)
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
SINGLETON_DEPENDENCY
public:
QUuid createRayPick(const QVariant& properties);
public slots:
Q_INVOKABLE QUuid createPick(const PickQuery::PickType type, const QVariant& properties);
Q_INVOKABLE void enablePick(const QUuid& uid);
Q_INVOKABLE void disablePick(const QUuid& uid);
Q_INVOKABLE void removePick(const QUuid& uid);
Q_INVOKABLE QVariantMap getPrevPickResult(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 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_PickScriptingInterface_h

View file

@ -0,0 +1,112 @@
//
// Created by Sam Gondelman 10/20/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 "PointerScriptingInterface.h"
#include <QtCore/QVariant>
#include <GLMHelpers.h>
#include "Application.h"
#include "LaserPointer.h"
void PointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const {
DependencyManager::get<PointerManager>()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void PointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const {
DependencyManager::get<PointerManager>()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}
QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType type, const QVariant& properties) const {
switch (type) {
case PickQuery::PickType::Ray:
return createLaserPointer(properties);
default:
return QUuid();
}
}
QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) const {
QVariantMap propertyMap = properties.toMap();
bool faceAvatar = false;
if (propertyMap["faceAvatar"].isValid()) {
faceAvatar = propertyMap["faceAvatar"].toBool();
}
bool centerEndY = true;
if (propertyMap["centerEndY"].isValid()) {
centerEndY = propertyMap["centerEndY"].toBool();
}
bool lockEnd = false;
if (propertyMap["lockEnd"].isValid()) {
lockEnd = propertyMap["lockEnd"].toBool();
}
bool distanceScaleEnd = false;
if (propertyMap["distanceScaleEnd"].isValid()) {
distanceScaleEnd = propertyMap["distanceScaleEnd"].toBool();
}
bool enabled = false;
if (propertyMap["enabled"].isValid()) {
enabled = propertyMap["enabled"].toBool();
}
LaserPointer::RenderStateMap renderStates;
if (propertyMap["renderStates"].isValid()) {
QList<QVariant> renderStateVariants = propertyMap["renderStates"].toList();
for (QVariant& renderStateVariant : renderStateVariants) {
if (renderStateVariant.isValid()) {
QVariantMap renderStateMap = renderStateVariant.toMap();
if (renderStateMap["name"].isValid()) {
std::string name = renderStateMap["name"].toString().toStdString();
renderStates[name] = LaserPointer::buildRenderState(renderStateMap);
}
}
}
}
LaserPointer::DefaultRenderStateMap defaultRenderStates;
if (propertyMap["defaultRenderStates"].isValid()) {
QList<QVariant> renderStateVariants = propertyMap["defaultRenderStates"].toList();
for (QVariant& renderStateVariant : renderStateVariants) {
if (renderStateVariant.isValid()) {
QVariantMap renderStateMap = renderStateVariant.toMap();
if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) {
std::string name = renderStateMap["name"].toString().toStdString();
float distance = renderStateMap["distance"].toFloat();
defaultRenderStates[name] = std::pair<float, RenderState>(distance, LaserPointer::buildRenderState(renderStateMap));
}
}
}
}
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<LaserPointer>(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled));
}
void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const {
QVariantMap propMap = properties.toMap();
QVariant startProps;
if (propMap["start"].isValid()) {
startProps = propMap["start"];
}
QVariant pathProps;
if (propMap["path"].isValid()) {
pathProps = propMap["path"];
}
QVariant endProps;
if (propMap["end"].isValid()) {
endProps = propMap["end"];
}
DependencyManager::get<PointerManager>()->editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps);
}

View file

@ -0,0 +1,42 @@
//
// Created by Sam Gondelman 10/20/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_PointerScriptingInterface_h
#define hifi_PointerScriptingInterface_h
#include <QtCore/QObject>
#include "DependencyManager.h"
#include <pointers/PointerManager.h>
#include <pointers/Pick.h>
class PointerScriptingInterface : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
QUuid createLaserPointer(const QVariant& properties) const;
public slots:
Q_INVOKABLE QUuid createPointer(const PickQuery::PickType type, const QVariant& properties) const;
Q_INVOKABLE void enablePointer(const QUuid& uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); }
Q_INVOKABLE void disablePointer(const QUuid& uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); }
Q_INVOKABLE void removePointer(const QUuid& uid) const { DependencyManager::get<PointerManager>()->removePointer(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 { DependencyManager::get<PointerManager>()->setRenderState(uid, renderState.toStdString()); }
Q_INVOKABLE QVariantMap getPrevPickResult(QUuid uid) const { return DependencyManager::get<PointerManager>()->getPrevPickResult(uid); }
Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get<PointerManager>()->setPrecisionPicking(uid, precisionPicking); }
Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get<PointerManager>()->setLength(uid, laserLength); }
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const;
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const;
Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay); }
};
#endif // hifi_PointerScriptingInterface_h

View file

@ -0,0 +1,51 @@
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RayPick.h"
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
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());
}
}
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());
}
}
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());
}
}
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

@ -0,0 +1,79 @@
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RayPick_h
#define hifi_RayPick_h
#include <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) {}
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,217 +0,0 @@
//
// RayPickManager.cpp
// interface/src/raypick
//
// 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 <pointers/rays/StaticRayPick.h>
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
#include "JointRayPick.h"
#include "MouseRayPick.h"
bool RayPickManager::checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) {
if (cache.contains(ray) && cache[ray].find(key) != cache[ray].end()) {
if (cache[ray][key].distance < res.distance) {
res = cache[ray][key];
}
return true;
}
return false;
}
void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache) {
if (intersects) {
cache[ray][key] = resTemp;
if (resTemp.distance < res.distance) {
res = resTemp;
}
} else {
cache[ray][key] = RayPickResult(res.searchRay);
}
}
void RayPickManager::update() {
RayPickCache results;
QHash<QUuid, RayPick::Pointer> cachedRayPicks;
withReadLock([&] {
cachedRayPicks = _rayPicks;
});
for (const auto& uid : cachedRayPicks.keys()) {
std::shared_ptr<RayPick> rayPick = cachedRayPicks[uid];
if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) {
continue;
}
PickRay ray;
{
bool valid;
ray = rayPick->getPickRay(valid);
if (!valid) {
continue;
}
}
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
RayPickResult res = RayPickResult(ray);
if (rayPick->getFilter().doesPickEntities()) {
RayToEntityIntersectionResult entityRes;
bool fromCache = true;
bool invisible = rayPick->getFilter().doesPickInvisible();
bool nonCollidable = rayPick->getFilter().doesPickNonCollidable();
RayCacheKey entityKey = { rayPick->getFilter().getEntityFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, entityKey)) {
entityRes = DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal),
entityKey, res, rayKey, results);
}
}
if (rayPick->getFilter().doesPickOverlays()) {
RayToOverlayIntersectionResult overlayRes;
bool fromCache = true;
bool invisible = rayPick->getFilter().doesPickInvisible();
bool nonCollidable = rayPick->getFilter().doesPickNonCollidable();
RayCacheKey overlayKey = { rayPick->getFilter().getOverlayFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, overlayKey)) {
overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
rayPick->getIncludeItemsAs<OverlayID>(), rayPick->getIgnoreItemsAs<OverlayID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal),
overlayKey, res, rayKey, results);
}
}
if (rayPick->getFilter().doesPickAvatars()) {
RayCacheKey avatarKey = { rayPick->getFilter().getAvatarFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, avatarKey)) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray,
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>());
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarKey, res, rayKey, results);
}
}
// Can't intersect with HUD in desktop mode
if (rayPick->getFilter().doesPickHUD() && DependencyManager::get<HMDScriptingInterface>()->isHMDMode()) {
RayCacheKey hudKey = { rayPick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(rayKey, results, res, hudKey)) {
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudKey, res, rayKey, results);
}
}
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
rayPick->setRayPickResult(res);
} else {
rayPick->setRayPickResult(RayPickResult(ray));
}
}
}
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, float maxDistance, bool enabled) {
auto newRayPick = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
QUuid id = QUuid::createUuid();
withWriteLock([&] {
_rayPicks[id] = newRayPick;
});
return id;
}
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid id = QUuid::createUuid();
auto newRayPick = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
});
return id;
}
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid id = QUuid::createUuid();
auto newRayPick = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
});
return id;
}
void RayPickManager::removeRayPick(const QUuid& uid) {
withWriteLock([&] {
_rayPicks.remove(uid);
});
}
RayPick::Pointer RayPickManager::findRayPick(const QUuid& uid) const {
return resultWithReadLock<RayPick::Pointer>([&] {
if (_rayPicks.contains(uid)) {
return _rayPicks[uid];
}
return RayPick::Pointer();
});
}
void RayPickManager::enableRayPick(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->enable();
}
}
void RayPickManager::disableRayPick(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->disable();
}
}
RayPickResult RayPickManager::getPrevRayPickResult(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
return rayPick->getPrevRayPickResult();
}
return RayPickResult();
}
void RayPickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setPrecisionPicking(precisionPicking);
}
}
void RayPickManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setIgnoreItems(ignore);
}
}
void RayPickManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setIncludeItems(include);
}
}

View file

@ -1,74 +0,0 @@
//
// RayPickManager.h
// interface/src/raypick
//
// 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 <memory>
#include <unordered_map>
#include <queue>
#include <QtCore/QObject>
#include <RegisteredMetaTypes.h>
#include <pointers/rays/RayPick.h>
class RayPickResult;
typedef struct RayCacheKey {
RayPickFilter::Flags mask;
QVector<QUuid> include;
QVector<QUuid> ignore;
bool operator==(const RayCacheKey& other) const {
return (mask == other.mask && include == other.include && ignore == other.ignore);
}
} RayCacheKey;
namespace std {
template <>
struct hash<RayCacheKey> {
size_t operator()(const RayCacheKey& k) const {
return ((hash<RayPickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
}
};
}
class RayPickManager : protected ReadWriteLockable {
public:
void update();
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled);
void removeRayPick(const QUuid& uid);
void enableRayPick(const QUuid& uid) const;
void disableRayPick(const QUuid& uid) const;
RayPickResult getPrevRayPickResult(const QUuid& uid) const;
void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const;
private:
RayPick::Pointer findRayPick(const QUuid& uid) const;
QHash<QUuid, RayPick::Pointer> _rayPicks;
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayCacheKey, RayPickResult>> RayPickCache;
// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer
bool checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key);
void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache);
};
#endif // hifi_RayPickManager_h

View file

@ -13,83 +13,42 @@
#include <QVariant>
#include "GLMHelpers.h"
#include "Application.h"
#include "PickScriptingInterface.h"
#include <pointers/PickManager.h>
#include "StaticRayPick.h"
#include "JointRayPick.h"
#include "MouseRayPick.h"
QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) {
QVariantMap propMap = properties.toMap();
bool enabled = false;
if (propMap["enabled"].isValid()) {
enabled = propMap["enabled"].toBool();
}
RayPickFilter filter = RayPickFilter();
if (propMap["filter"].isValid()) {
filter = RayPickFilter(propMap["filter"].toUInt());
}
float maxDistance = 0.0f;
if (propMap["maxDistance"].isValid()) {
maxDistance = propMap["maxDistance"].toFloat();
}
if (propMap["joint"].isValid()) {
std::string jointName = propMap["joint"].toString().toStdString();
if (jointName != "Mouse") {
// x = upward, y = forward, z = lateral
glm::vec3 posOffset = Vectors::ZERO;
if (propMap["posOffset"].isValid()) {
posOffset = vec3FromVariant(propMap["posOffset"]);
}
glm::vec3 dirOffset = Vectors::UP;
if (propMap["dirOffset"].isValid()) {
dirOffset = vec3FromVariant(propMap["dirOffset"]);
}
return qApp->getRayPickManager().createRayPick(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
} else {
return qApp->getRayPickManager().createRayPick(filter, maxDistance, enabled);
}
} else if (propMap["position"].isValid()) {
glm::vec3 position = vec3FromVariant(propMap["position"]);
glm::vec3 direction = -Vectors::UP;
if (propMap["direction"].isValid()) {
direction = vec3FromVariant(propMap["direction"]);
}
return qApp->getRayPickManager().createRayPick(position, direction, filter, maxDistance, enabled);
}
return QUuid();
return DependencyManager::get<PickScriptingInterface>()->createRayPick(properties);
}
void RayPickScriptingInterface::enableRayPick(const QUuid& uid) {
qApp->getRayPickManager().enableRayPick(uid);
DependencyManager::get<PickManager>()->enablePick(uid);
}
void RayPickScriptingInterface::disableRayPick(const QUuid& uid) {
qApp->getRayPickManager().disableRayPick(uid);
DependencyManager::get<PickManager>()->disablePick(uid);
}
void RayPickScriptingInterface::removeRayPick(const QUuid& uid) {
qApp->getRayPickManager().removeRayPick(uid);
DependencyManager::get<PickManager>()->removePick(uid);
}
RayPickResult RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) {
return qApp->getRayPickManager().getPrevRayPickResult(uid);
QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) {
return DependencyManager::get<PickManager>()->getPrevPickResult(uid);
}
void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) {
qApp->getRayPickManager().setPrecisionPicking(uid, precisionPicking);
DependencyManager::get<PickManager>()->setPrecisionPicking(uid, precisionPicking);
}
void RayPickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) {
qApp->getRayPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
DependencyManager::get<PickManager>()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void RayPickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) {
qApp->getRayPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
DependencyManager::get<PickManager>()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}

View file

@ -13,26 +13,11 @@
#include <QtCore/QObject>
#include <RegisteredMetaTypes.h>
#include "RegisteredMetaTypes.h"
#include <DependencyManager.h>
#include <pointers/rays/RayPick.h>
class RayPickScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT)
Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT)
Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT)
Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT)
Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT)
Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT)
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
SINGLETON_DEPENDENCY
public slots:
@ -40,26 +25,11 @@ 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);
unsigned int PICK_NOTHING() { return 0; }
unsigned int PICK_ENTITIES() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ENTITIES); }
unsigned int PICK_OVERLAYS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_OVERLAYS); }
unsigned int PICK_AVATARS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_AVATARS); }
unsigned int PICK_HUD() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_HUD); }
unsigned int PICK_COARSE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COARSE); }
unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); }
unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); }
unsigned int PICK_ALL_INTERSECTIONS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ALL_INTERSECTIONS); }
unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; }
unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; }
unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; }
unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; }
unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; }
};
#endif // hifi_RayPickScriptingInterface_h

View file

@ -7,13 +7,12 @@
//
#include "StaticRayPick.h"
StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) :
StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled) :
RayPick(filter, maxDistance, enabled),
_pickRay(position, direction)
{
}
const PickRay StaticRayPick::getPickRay(bool& valid) const {
valid = true;
const PickRay StaticRayPick::getMathematicalPick() const {
return _pickRay;
}

View file

@ -13,9 +13,9 @@
class StaticRayPick : public RayPick {
public:
StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getPickRay(bool& valid) const override;
const PickRay getMathematicalPick() const override;
private:
PickRay _pickRay;

View file

@ -0,0 +1,80 @@
//
// Created by Sam Gondelman 10/17/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Pick.h"
const PickFilter PickFilter::NOTHING;
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

@ -1,22 +1,32 @@
//
// Created by Sam Gondelman 7/11/2017
// Created by Sam Gondelman 10/17/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RayPick_h
#define hifi_RayPick_h
#ifndef hifi_Pick_h
#define hifi_Pick_h
#include <memory>
#include <stdint.h>
#include <bitset>
#include <QtCore/QUuid>
#include <QVector>
#include <QVariant>
#include <RegisteredMetaTypes.h>
#include <shared/ReadWriteLockable.h>
class RayPickFilter {
enum IntersectionType {
NONE = 0,
ENTITY,
OVERLAY,
AVATAR,
HUD
};
class PickFilter {
public:
enum FlagBit {
PICK_ENTITIES = 0,
@ -39,11 +49,11 @@ public:
// The key is the Flags
Flags _flags;
RayPickFilter() {}
RayPickFilter(const Flags& flags) : _flags(flags) {}
PickFilter() {}
PickFilter(const Flags& flags) : _flags(flags) {}
bool operator== (const RayPickFilter& rhs) const { return _flags == rhs._flags; }
bool operator!= (const RayPickFilter& rhs) const { return _flags != rhs._flags; }
bool operator== (const PickFilter& rhs) const { return _flags == rhs._flags; }
bool operator!= (const PickFilter& rhs) const { return _flags != rhs._flags; }
void setFlag(FlagBit flag, bool value) { _flags[flag] = value; }
@ -91,36 +101,63 @@ public:
static constexpr unsigned int getBitMask(FlagBit bit) { return 1 << bit; }
static const RayPickFilter NOTHING;
static const PickFilter NOTHING;
};
class RayPick : protected ReadWriteLockable {
class PickResult {
public:
using Pointer = std::shared_ptr<RayPick>;
PickResult() {}
PickResult(const QVariantMap& pickVariant) : pickVariant(pickVariant) {}
RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
virtual QVariantMap toVariantMap() const {
return pickVariant;
}
virtual const PickRay getPickRay(bool& valid) const = 0;
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>;
class PickQuery : protected ReadWriteLockable {
Q_GADGET
public:
PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled);
enum PickType {
Ray = 0,
Stylus
};
Q_ENUM(PickType)
void enable(bool enabled = true);
void disable() { enable(false); }
RayPickFilter getFilter() const;
PickFilter getFilter() const;
float getMaxDistance() const;
bool isEnabled() const;
RayPickResult getPrevRayPickResult() const;
void setPrecisionPicking(bool precisionPicking);
void setRayPickResult(const RayPickResult& rayPickResult);
PickResultPointer getPrevPickResult() const;
void setPickResult(const PickResultPointer& pickResult);
QVector<QUuid> getIgnoreItems() const;
QVector<QUuid> getIncludeItems() const;
template <typename T>
QVector<T> getIgnoreItemsAs() const {
QVector<T> result;
template <typename S>
QVector<S> getIgnoreItemsAs() const {
QVector<S> result;
withReadLock([&] {
for (const auto& uid : _ignoreItems) {
result.push_back(uid);
@ -129,9 +166,9 @@ public:
return result;
}
template <typename T>
QVector<T> getIncludeItemsAs() const {
QVector<T> result;
template <typename S>
QVector<S> getIncludeItemsAs() const {
QVector<S> result;
withReadLock([&] {
for (const auto& uid : _includeItems) {
result.push_back(uid);
@ -144,13 +181,26 @@ public:
void setIncludeItems(const QVector<QUuid>& items);
private:
RayPickFilter _filter;
PickFilter _filter;
const float _maxDistance;
bool _enabled;
RayPickResult _prevResult;
PickResultPointer _prevResult;
QVector<QUuid> _ignoreItems;
QVector<QUuid> _includeItems;
};
#endif // hifi_RayPick_h
template<typename T>
class Pick : public PickQuery {
public:
Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, 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;
};
#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(PickQuery::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<PickQuery::PickType, QHash<QUuid, std::shared_ptr<PickQuery>>> cachedPicks;
withReadLock([&] {
cachedPicks = _picks;
});
bool shouldPickHUD = _shouldPickHUDOperator();
_rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], shouldPickHUD);
}

View file

@ -0,0 +1,48 @@
//
// Created by Sam Gondelman 10/16/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_PickManager_h
#define hifi_PickManager_h
#include <DependencyManager.h>
#include "RegisteredMetaTypes.h"
#include "Pick.h"
#include "PickCacheOptimizer.h"
class PickManager : public Dependency, protected ReadWriteLockable {
SINGLETON_DEPENDENCY
public:
PickManager();
void update();
QUuid addPick(PickQuery::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::function<bool()> _shouldPickHUDOperator;
std::shared_ptr<PickQuery> findPick(const QUuid& uid) const;
QHash<PickQuery::PickType, QHash<QUuid, std::shared_ptr<PickQuery>>> _picks;
QHash<QUuid, PickQuery::PickType> _typeMap;
PickCacheOptimizer<PickRay> _rayPickCacheOptimizer;
};
#endif // hifi_PickManager_h

View file

@ -0,0 +1,39 @@
//
// 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 "Pointer.h"
#include <DependencyManager.h>
#include "PickManager.h"
Pointer::~Pointer() {
DependencyManager::get<PickManager>()->removePick(_pickUID);
}
void Pointer::enable() {
DependencyManager::get<PickManager>()->enablePick(_pickUID);
}
void Pointer::disable() {
DependencyManager::get<PickManager>()->disablePick(_pickUID);
}
const QVariantMap Pointer::getPrevPickResult() {
return DependencyManager::get<PickManager>()->getPrevPickResult(_pickUID);
}
void Pointer::setPrecisionPicking(const bool precisionPicking) {
DependencyManager::get<PickManager>()->setPrecisionPicking(_pickUID, precisionPicking);
}
void Pointer::setIgnoreItems(const QVector<QUuid>& ignoreItems) const {
DependencyManager::get<PickManager>()->setIgnoreItems(_pickUID, ignoreItems);
}
void Pointer::setIncludeItems(const QVector<QUuid>& includeItems) const {
DependencyManager::get<PickManager>()->setIncludeItems(_pickUID, includeItems);
}

View file

@ -0,0 +1,46 @@
//
// Created by Sam Gondelman 10/17/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_Pointer_h
#define hifi_Pointer_h
#include <QtCore/QUuid>
#include <QVector>
#include <QVariant>
#include <shared/ReadWriteLockable.h>
class Pointer : protected ReadWriteLockable {
public:
Pointer(const QUuid& uid) : _pickUID(uid) {}
virtual ~Pointer();
virtual void enable();
virtual void disable();
virtual const QVariantMap getPrevPickResult();
virtual void setRenderState(const std::string& state) = 0;
virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) = 0;
virtual void setPrecisionPicking(const bool precisionPicking);
virtual void setIgnoreItems(const QVector<QUuid>& ignoreItems) const;
virtual void setIncludeItems(const QVector<QUuid>& includeItems) const;
// Pointers can choose to implement these
virtual void setLength(const float length) {}
virtual void setLockEndUUID(QUuid objectID, const bool isOverlay) {}
virtual void update() = 0;
QUuid getRayUID() { return _pickUID; }
protected:
const QUuid _pickUID;
};
#endif // hifi_Pick_h

View file

@ -1,6 +1,115 @@
//
// Created by Bradley Austin Davis on 2017/10/16
// Copyright 2013-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 "PointerManager.h"
PointerManager::PointerManager() {
std::shared_ptr<Pointer> PointerManager::find(const QUuid& uid) const {
return resultWithReadLock<std::shared_ptr<Pointer>>([&] {
auto itr = _pointers.find(uid);
if (itr != _pointers.end()) {
return *itr;
}
return std::shared_ptr<Pointer>();
});
}
QUuid PointerManager::addPointer(std::shared_ptr<Pointer> pointer) {
QUuid result;
if (!pointer->getRayUID().isNull()) {
result = QUuid::createUuid();
withWriteLock([&] { _pointers[result] = pointer; });
}
return result;
}
void PointerManager::removePointer(const QUuid& uid) {
withWriteLock([&] {
_pointers.remove(uid);
});
}
void PointerManager::enablePointer(const QUuid& uid) const {
auto pointer = find(uid);
if (pointer) {
pointer->enable();
}
}
void PointerManager::disablePointer(const QUuid& uid) const {
auto pointer = find(uid);
if (pointer) {
pointer->disable();
}
}
void PointerManager::setRenderState(const QUuid& uid, const std::string& renderState) const {
auto pointer = find(uid);
if (pointer) {
pointer->setRenderState(renderState);
}
}
void PointerManager::editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const {
auto pointer = find(uid);
if (pointer) {
pointer->editRenderState(state, startProps, pathProps, endProps);
}
}
const QVariantMap PointerManager::getPrevPickResult(const QUuid& uid) const {
auto pointer = find(uid);
if (pointer) {
return pointer->getPrevPickResult();
}
return QVariantMap();
}
void PointerManager::update() {
auto cachedPointers = resultWithReadLock<QList<std::shared_ptr<Pointer>>>([&] {
return _pointers.values();
});
for (const auto& pointer : cachedPointers) {
pointer->update();
}
}
void PointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const {
auto pointer = find(uid);
if (pointer) {
pointer->setPrecisionPicking(precisionPicking);
}
}
void PointerManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const {
auto pointer = find(uid);
if (pointer) {
pointer->setIgnoreItems(ignoreEntities);
}
}
void PointerManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const {
auto pointer = find(uid);
if (pointer) {
pointer->setIncludeItems(includeEntities);
}
}
void PointerManager::setLength(const QUuid& uid, const float length) const {
auto pointer = find(uid);
if (pointer) {
pointer->setLength(length);
}
}
void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const {
auto pointer = find(uid);
if (pointer) {
pointer->setLockEndUUID(objectID, isOverlay);
}
}

View file

@ -11,11 +11,38 @@
#include <DependencyManager.h>
#include <PointerEvent.h>
class PointerManager : public QObject, public Dependency {
#include <memory>
#include <shared/ReadWriteLockable.h>
#include "Pointer.h"
class PointerManager : public QObject, public Dependency, protected ReadWriteLockable {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
PointerManager();
PointerManager() {}
QUuid addPointer(std::shared_ptr<Pointer> pointer);
void removePointer(const QUuid& uid);
void enablePointer(const QUuid& uid) const;
void disablePointer(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 QVariantMap getPrevPickResult(const QUuid& uid) const;
void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const;
void setLength(const QUuid& uid, const float length) const;
void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const;
void update();
private:
std::shared_ptr<Pointer> find(const QUuid& uid) const;
QHash<QUuid, std::shared_ptr<Pointer>> _pointers;
signals:
void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent);

View file

@ -1,81 +0,0 @@
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RayPick.h"
const RayPickFilter RayPickFilter::NOTHING;
RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled)
{
}
void RayPick::enable(bool enabled) {
withWriteLock([&] {
_enabled = enabled;
});
}
RayPickFilter RayPick::getFilter() const {
return resultWithReadLock<RayPickFilter>([&] {
return _filter;
});
}
float RayPick::getMaxDistance() const {
return _maxDistance;
}
bool RayPick::isEnabled() const {
return resultWithReadLock<bool>([&] {
return _enabled;
});
}
void RayPick::setPrecisionPicking(bool precisionPicking) {
withWriteLock([&]{
_filter.setFlag(RayPickFilter::PICK_COARSE, !precisionPicking);
});
}
void RayPick::setRayPickResult(const RayPickResult& rayPickResult) {
withWriteLock([&] {
_prevResult = rayPickResult;
});
}
QVector<QUuid> RayPick::getIgnoreItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _ignoreItems;
});
}
QVector<QUuid> RayPick::getIncludeItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _includeItems;
});
}
RayPickResult RayPick::getPrevRayPickResult() const {
return resultWithReadLock<RayPickResult>([&] {
return _prevResult;
});
}
void RayPick::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
withWriteLock([&] {
_ignoreItems = ignoreItems;
});
}
void RayPick::setIncludeItems(const QVector<QUuid>& includeItems) {
withWriteLock([&] {
_includeItems = includeItems;
});
}

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

@ -125,42 +125,51 @@ 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(0.0f), direction(0.0f) { }
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;
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 override {
QVariantMap pickRay;
pickRay["origin"] = vec3toVariant(origin);
pickRay["direction"] = vec3toVariant(direction);
return pickRay;
}
};
namespace std {
template <>
struct hash<glm::vec3> {
size_t operator()(const glm::vec3& a) const {
return ((hash<float>()(a.x) ^ (hash<float>()(a.y) << 1)) >> 1) ^ (hash<float>()(a.z) << 1);
}
};
template <>
struct hash<PickRay> {
size_t operator()(const PickRay& a) const {
return (hash<glm::vec3>()(a.origin) ^ (hash<glm::vec3>()(a.direction) << 1));
}
};
}
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,

View file

@ -252,7 +252,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
length: 1000
};
if (rayPicks[h].type === RayPick.INTERSECTED_ENTITY) {
if (rayPicks[h].type === Picks.INTERSECTED_ENTITY) {
// XXX check to make sure this one isn't already in nearbyEntityProperties?
if (rayPicks[h].distance < NEAR_GRAB_PICK_RADIUS * sensorScaleFactor) {
var nearEntityID = rayPicks[h].objectID;
@ -390,35 +390,35 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
this.leftControllerRayPick = RayPick.createRayPick({
joint: "_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS,
enabled: true,
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
});
this.leftControllerHudRayPick = RayPick.createRayPick({
joint: "_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_HUD,
filter: Picks.PICK_HUD,
enabled: true,
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
});
this.rightControllerRayPick = RayPick.createRayPick({
joint: "_CONTROLLER_RIGHTHAND",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS,
enabled: true,
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true)
});
this.rightControllerHudRayPick = RayPick.createRayPick({
joint: "_CONTROLLER_RIGHTHAND",
filter: RayPick.PICK_HUD,
filter: Picks.PICK_HUD,
enabled: true,
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true)
});
this.mouseRayPick = RayPick.createRayPick({
joint: "Mouse",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS,
enabled: true
});

View file

@ -373,8 +373,8 @@ Script.include("/~/system/libraries/controllers.js");
var entityType = entityProperty.type;
var hudRayPick = controllerData.hudRayPicks[this.hand];
var point2d = this.calculateNewReticlePosition(hudRayPick.intersection);
if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web") ||
intersection.type === RayPick.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) {
if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") ||
intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) {
return true;
}
return false;
@ -494,7 +494,7 @@ Script.include("/~/system/libraries/controllers.js");
}
var rayPickInfo = controllerData.rayPicks[this.hand];
if (rayPickInfo.type === RayPick.INTERSECTED_ENTITY) {
if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) {
if (controllerData.triggerClicks[this.hand]) {
var entityID = rayPickInfo.objectID;
var targetProps = Entities.getEntityProperties(entityID, [
@ -578,7 +578,7 @@ Script.include("/~/system/libraries/controllers.js");
this.laserPointer = LaserPointers.createLaserPointer({
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS,
maxDistance: PICK_MAX_DISTANCE,
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,

View file

@ -184,7 +184,7 @@ Script.include("/~/system/libraries/controllers.js");
this.laserPointer = LaserPointers.createLaserPointer({
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS,
maxDistance: PICK_MAX_DISTANCE,
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,

View file

@ -207,7 +207,7 @@
this.laserPointer = LaserPointers.createLaserPointer({
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_HUD,
filter: Picks.PICK_HUD,
maxDistance: PICK_MAX_DISTANCE,
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,

View file

@ -146,12 +146,12 @@ Script.include("/~/system/libraries/utils.js");
this.sendPickData = function(controllerData) {
if (controllerData.triggerClicks[this.hand] && !this.triggerClicked) {
var intersection = controllerData.rayPicks[this.hand];
if (intersection.type === RayPick.INTERSECTED_ENTITY) {
if (intersection.type === Picks.INTERSECTED_ENTITY) {
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
method: "selectEntity",
entityID: intersection.objectID
}));
} else if (intersection.type === RayPick.INTERSECTED_OVERLAY) {
} else if (intersection.type === Picks.INTERSECTED_OVERLAY) {
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
method: "selectOverlay",
overlayID: intersection.objectID
@ -232,7 +232,7 @@ Script.include("/~/system/libraries/utils.js");
this.laserPointer = LaserPointers.createLaserPointer({
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS,
maxDistance: PICK_MAX_DISTANCE,
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,

View file

@ -294,7 +294,7 @@ Script.include("/~/system/libraries/controllers.js");
this.shouldExit = function(controllerData) {
var intersection = controllerData.rayPicks[this.hand];
var offOverlay = (intersection.type !== RayPick.INTERSECTED_OVERLAY);
var offOverlay = (intersection.type !== Picks.INTERSECTED_OVERLAY);
var triggerOff = (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE);
if (triggerOff) {
this.deleteContextOverlay();
@ -366,7 +366,7 @@ Script.include("/~/system/libraries/controllers.js");
this.laserPointer = LaserPointers.createLaserPointer({
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_OVERLAYS,
filter: Picks.PICK_OVERLAYS,
maxDistance: PICK_MAX_DISTANCE,
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,

View file

@ -151,7 +151,7 @@ Script.include("/~/system/libraries/controllers.js");
this.teleportRayHandVisible = LaserPointers.createLaserPointer({
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
filter: RayPick.PICK_ENTITIES,
filter: Picks.PICK_ENTITIES,
faceAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates,
@ -159,14 +159,14 @@ Script.include("/~/system/libraries/controllers.js");
});
this.teleportRayHandInvisible = LaserPointers.createLaserPointer({
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE,
filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE,
faceAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates
});
this.teleportRayHeadVisible = LaserPointers.createLaserPointer({
joint: "Avatar",
filter: RayPick.PICK_ENTITIES,
filter: Picks.PICK_ENTITIES,
faceAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates,
@ -174,7 +174,7 @@ Script.include("/~/system/libraries/controllers.js");
});
this.teleportRayHeadInvisible = LaserPointers.createLaserPointer({
joint: "Avatar",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE,
filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE,
faceAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates
@ -399,7 +399,7 @@ Script.include("/~/system/libraries/controllers.js");
// you can't teleport there.
var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70;
function getTeleportTargetType(result) {
if (result.type === RayPick.INTERSECTED_NONE) {
if (result.type === Picks.INTERSECTED_NONE) {
return TARGET.NONE;
}

View file

@ -379,7 +379,7 @@ Script.include("/~/system/libraries/controllers.js");
var entityProperty = Entities.getEntityProperties(intersection.objectID);
var entityType = entityProperty.type;
if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web")) {
if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web")) {
return true;
}
return false;
@ -447,7 +447,7 @@ Script.include("/~/system/libraries/controllers.js");
this.laserPointer = LaserPointers.createLaserPointer({
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
filter: RayPick.PICK_ENTITIES,
filter: Picks.PICK_ENTITIES,
maxDistance: PICK_MAX_DISTANCE,
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,

View file

@ -260,14 +260,14 @@ function Grabber() {
this.mouseRayOverlays = RayPick.createRayPick({
joint: "Mouse",
filter: RayPick.PICK_OVERLAYS,
filter: Picks.PICK_OVERLAYS,
enabled: true
});
RayPick.setIncludeItems(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]);
var renderStates = [{name: "grabbed", end: beacon}];
this.mouseRayEntities = LaserPointers.createLaserPointer({
joint: "Mouse",
filter: RayPick.PICK_ENTITIES,
filter: Picks.PICK_ENTITIES,
faceAvatar: true,
enabled: true,
renderStates: renderStates
@ -321,12 +321,12 @@ Grabber.prototype.pressEvent = function(event) {
}
var overlayResult = RayPick.getPrevRayPickResult(this.mouseRayOverlays);
if (overlayResult.type != RayPick.INTERSECTED_NONE) {
if (overlayResult.type != Picks.INTERSECTED_NONE) {
return;
}
var pickResults = LaserPointers.getPrevRayPickResult(this.mouseRayEntities);
if (pickResults.type == RayPick.INTERSECTED_NONE) {
if (pickResults.type == Picks.INTERSECTED_NONE) {
LaserPointers.setRenderState(this.mouseRayEntities, "");
return;
}

View file

@ -130,7 +130,7 @@ function sendTouchMoveEventToTouchTarget(hand, touchTarget) {
}
function composeTouchTargetFromIntersection(intersection) {
var isEntity = (intersection.type === RayPick.INTERSECTED_ENTITY);
var isEntity = (intersection.type === Picks.INTERSECTED_ENTITY);
var objectID = intersection.objectID;
var worldPos = intersection.intersection;
var props = null;