control hovering, preset buttons for clicking, constness, scroll off

surface
This commit is contained in:
SamGondelman 2017-10-27 10:39:37 -07:00
parent 7951826e49
commit e9a5acda06
7 changed files with 100 additions and 43 deletions

View file

@ -17,9 +17,9 @@
#include <pointers/PickManager.h>
#include "PickScriptingInterface.h"
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) :
Pointer(DependencyManager::get<PickScriptingInterface>()->createRayPick(rayProps), enabled),
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover,
const PointerTriggers& triggers, bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled) :
Pointer(DependencyManager::get<PickScriptingInterface>()->createRayPick(rayProps), enabled, hover),
_triggers(triggers),
_renderStates(renderStates),
_defaultRenderStates(defaultRenderStates),
@ -83,7 +83,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
}
}
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState) {
if (!renderState.getStartID().isNull()) {
QVariantMap startProps;
startProps.insert("position", vec3toVariant(pickRay.origin));
@ -210,13 +210,13 @@ Pointer::Buttons LaserPointer::getPressedButtons() {
return toReturn;
}
void LaserPointer::setLength(const float length) {
void LaserPointer::setLength(float length) {
withWriteLock([&] {
_laserLength = length;
});
}
void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) {
void LaserPointer::setLockEndUUID(const QUuid& objectID, bool isOverlay) {
withWriteLock([&] {
_objectLockEnd = std::pair<QUuid, bool>(objectID, isOverlay);
});
@ -281,21 +281,49 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) {
return RenderState(startID, pathID, endID);
}
PointerEvent LaserPointer::buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const {
PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const {
uint32_t id = 0;
glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]);
glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]);
glm::vec3 direction = -surfaceNormal;
IntersectionType type = IntersectionType(pickResult["type"].toUInt());
QUuid pickedID = pickResult["objectID"].toUuid();
glm::vec2 pos2D;
if (type == ENTITY) {
pos2D = projectOntoEntityXYPlane(uid, intersection);
} else if (type == OVERLAY) {
pos2D = projectOntoOverlayXYPlane(uid, intersection);
if (pickedID != target.objectID) {
QVariantMap searchRay = pickResult["searchRay"].toMap();
glm::vec3 origin = vec3FromVariant(searchRay["origin"]);
glm::vec3 direction = vec3FromVariant(searchRay["direction"]);
if (target.type == ENTITY) {
intersection = intersectRayWithEntityXYPlane(target.objectID, origin, direction);
} else if (target.type == OVERLAY) {
intersection = intersectRayWithOverlayXYPlane(target.objectID, origin, direction);
}
}
if (target.type == ENTITY) {
pos2D = projectOntoEntityXYPlane(target.objectID, intersection);
} else if (target.type == OVERLAY) {
pos2D = projectOntoOverlayXYPlane(target.objectID, intersection);
}
return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons);
}
glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const {
glm::vec3 n = rotation * Vectors::FRONT;
float t = glm::dot(n, point - origin) / glm::dot(n, direction);
return origin + t * direction;
}
glm::vec3 LaserPointer::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const {
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f);
return intersectRayWithXYPlane(origin, direction, position, rotation, DEFAULT_REGISTRATION_POINT);
}
glm::vec3 LaserPointer::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint());
}
glm::vec2 LaserPointer::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const {
glm::quat invRot = glm::inverse(rotation);
glm::vec3 localPos = invRot * (worldPos - position);
@ -325,7 +353,7 @@ glm::vec2 LaserPointer::projectOntoOverlayXYPlane(const QUuid& overlayID, const
return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT);
}
glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entity);
glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint());
}

View file

@ -54,16 +54,16 @@ public:
typedef std::unordered_map<std::string, RenderState> RenderStateMap;
typedef std::unordered_map<std::string, std::pair<float, RenderState>> DefaultRenderStateMap;
LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers,
bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled);
~LaserPointer();
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) override;
void setLength(const float length) override;
void setLockEndUUID(QUuid objectID, const bool isOverlay) override;
void setLength(float length) override;
void setLockEndUUID(const QUuid& objectID, bool isOverlay) override;
void updateVisuals(const QVariantMap& prevRayPickResult) override;
@ -73,7 +73,7 @@ public:
static RenderState buildRenderState(const QVariantMap& propMap);
protected:
PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const override;
PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const override;
private:
PointerTriggers _triggers;
@ -88,10 +88,14 @@ private:
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
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 updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState);
void disableRenderState(const RenderState& renderState);
glm::vec2 projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const;
glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const;
glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const;
glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const;
glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const;
glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const;
glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const;

View file

@ -87,6 +87,11 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties)
}
}
bool hover = false;
if (propertyMap["hover"].isValid()) {
hover = propertyMap["hover"].toBool();
}
PointerTriggers triggers;
auto userInputMapper = DependencyManager::get<UserInputMapper>();
if (propertyMap["triggers"].isValid()) {
@ -105,7 +110,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties)
}
}
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<LaserPointer>(properties, renderStates, defaultRenderStates, triggers,
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<LaserPointer>(properties, renderStates, defaultRenderStates, hover, triggers,
faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled));
}

View file

@ -33,7 +33,7 @@ const QVariantMap Pointer::getPrevPickResult() {
return DependencyManager::get<PickManager>()->getPrevPickResult(_pickUID);
}
void Pointer::setPrecisionPicking(const bool precisionPicking) {
void Pointer::setPrecisionPicking(bool precisionPicking) {
DependencyManager::get<PickManager>()->setPrecisionPicking(_pickUID, precisionPicking);
}
@ -60,16 +60,17 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) {
// Hover events
Pointer::PickedObject hoveredObject = getHoveredObject(pickResult);
PointerEvent hoveredEvent = buildPointerEvent(hoveredObject.objectID, pickResult);
PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult);
hoveredEvent.setType(PointerEvent::Move);
// TODO: set buttons on hover events
hoveredEvent.setButton(PointerEvent::NoButtons);
if (_enabled) {
if (_enabled && _hover) {
if (hoveredObject.type == OVERLAY) {
if (_prevHoveredObject.type == OVERLAY) {
if (hoveredObject.objectID == _prevHoveredObject.objectID) {
emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent);
} else {
PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult);
PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult);
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent);
emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent);
}
@ -87,7 +88,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) {
if (hoveredObject.objectID == _prevHoveredObject.objectID) {
emit pointerManager->hoverContinueEntity(hoveredObject.objectID, hoveredEvent);
} else {
PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult);
PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult);
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent);
emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent);
}
@ -122,7 +123,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) {
const std::string SHOULD_FOCUS_BUTTON = "Focus";
for (const std::string& button : newButtons) {
hoveredEvent.setType(PointerEvent::Press);
hoveredEvent.setButton(PointerEvent::PrimaryButton);
hoveredEvent.setButton(chooseButton(button));
hoveredEvent.setShouldFocus(button == SHOULD_FOCUS_BUTTON);
if (hoveredObject.type == ENTITY) {
emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent);
@ -134,9 +135,9 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) {
// Trigger continue
for (const std::string& button : sameButtons) {
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult);
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult);
triggeredEvent.setType(PointerEvent::Move);
triggeredEvent.setButton(PointerEvent::PrimaryButton);
hoveredEvent.setButton(chooseButton(button));
if (_triggeredObjects[button].type == ENTITY) {
emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent);
} else if (_triggeredObjects[button].type == OVERLAY) {
@ -146,9 +147,9 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) {
// Trigger end
for (const std::string& button : _prevButtons) {
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult);
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult);
triggeredEvent.setType(PointerEvent::Release);
triggeredEvent.setButton(PointerEvent::PrimaryButton);
hoveredEvent.setButton(chooseButton(button));
if (_triggeredObjects[button].type == ENTITY) {
emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent);
} else if (_triggeredObjects[button].type == OVERLAY) {
@ -159,4 +160,19 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) {
_prevHoveredObject = hoveredObject;
_prevButtons = buttons;
}
PointerEvent::Button Pointer::chooseButton(const std::string& button) {
const std::string PRIMARY_BUTTON = "Primary";
const std::string SECONDARY_BUTTON = "Secondary";
const std::string TERTIARY_BUTTON = "Tertiary";
if (button == PRIMARY_BUTTON) {
return PointerEvent::PrimaryButton;
} else if (button == SECONDARY_BUTTON) {
return PointerEvent::SecondaryButton;
} else if (button == TERTIARY_BUTTON) {
return PointerEvent::TertiaryButton;
} else {
return PointerEvent::NoButtons;
}
}

View file

@ -38,7 +38,7 @@ using PointerTriggers = std::vector<PointerTrigger>;
class Pointer : protected ReadWriteLockable {
public:
Pointer(const QUuid& uid, bool enabled) : _pickUID(uid), _enabled(enabled) {}
Pointer(const QUuid& uid, bool enabled, bool hover) : _pickUID(uid), _enabled(enabled), _hover(hover) {}
virtual ~Pointer();
@ -49,13 +49,13 @@ public:
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 setPrecisionPicking(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 setLength(float length) {}
virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {}
void update();
virtual void updateVisuals(const QVariantMap& pickResult) = 0;
@ -79,13 +79,17 @@ public:
protected:
const QUuid _pickUID;
bool _enabled;
bool _hover;
virtual PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const = 0;
virtual PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const = 0;
private:
PickedObject _prevHoveredObject;
Buttons _prevButtons;
std::unordered_map<std::string, PickedObject> _triggeredObjects;
PointerEvent::Button chooseButton(const std::string& button);
};
#endif // hifi_Pick_h

View file

@ -79,7 +79,7 @@ void PointerManager::update() {
}
}
void PointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const {
void PointerManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto pointer = find(uid);
if (pointer) {
pointer->setPrecisionPicking(precisionPicking);
@ -100,14 +100,14 @@ void PointerManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& inc
}
}
void PointerManager::setLength(const QUuid& uid, const float length) const {
void PointerManager::setLength(const QUuid& uid, 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 {
void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const {
auto pointer = find(uid);
if (pointer) {
pointer->setLockEndUUID(objectID, isOverlay);

View file

@ -31,12 +31,12 @@ public:
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 setPrecisionPicking(const QUuid& uid, 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 setLength(const QUuid& uid, float length) const;
void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const;
void update();