mirror of
https://github.com/overte-org/overte.git
synced 2025-04-30 03:42:34 +02:00
263 lines
11 KiB
C++
263 lines
11 KiB
C++
//
|
|
// 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"
|
|
#include "PointerManager.h"
|
|
|
|
#include "NumericalConstants.h"
|
|
|
|
const float Pointer::POINTER_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
|
const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
|
const float Pointer::TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED = TOUCH_PRESS_TO_MOVE_DEADSPOT * TOUCH_PRESS_TO_MOVE_DEADSPOT;
|
|
|
|
Pointer::~Pointer() {
|
|
DependencyManager::get<PickManager>()->removePick(_pickUID);
|
|
}
|
|
|
|
void Pointer::enable() {
|
|
DependencyManager::get<PickManager>()->enablePick(_pickUID);
|
|
withWriteLock([&] {
|
|
_enabled = true;
|
|
});
|
|
}
|
|
|
|
void Pointer::disable() {
|
|
// Disable the pointer first, then the pick, so someone can't try to use it while it's in a bad state
|
|
withWriteLock([&] {
|
|
_enabled = false;
|
|
});
|
|
DependencyManager::get<PickManager>()->disablePick(_pickUID);
|
|
}
|
|
|
|
PickResultPointer Pointer::getPrevPickResult() {
|
|
return DependencyManager::get<PickManager>()->getPrevPickResult(_pickUID);
|
|
}
|
|
|
|
void Pointer::setPrecisionPicking(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);
|
|
}
|
|
|
|
bool Pointer::isLeftHand() const {
|
|
return DependencyManager::get<PickManager>()->isLeftHand(_pickUID);
|
|
}
|
|
|
|
bool Pointer::isRightHand() const {
|
|
return DependencyManager::get<PickManager>()->isRightHand(_pickUID);
|
|
}
|
|
|
|
bool Pointer::isMouse() const {
|
|
return DependencyManager::get<PickManager>()->isMouse(_pickUID);
|
|
}
|
|
|
|
void Pointer::update(unsigned int pointerID) {
|
|
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
|
withReadLock([&] {
|
|
auto pickResult = getPrevPickResult();
|
|
// Pointer needs its own PickResult object so it doesn't modify the cached pick result
|
|
auto visualPickResult = getVisualPickResult(getPickResultCopy(pickResult));
|
|
updateVisuals(visualPickResult);
|
|
generatePointerEvents(pointerID, visualPickResult);
|
|
});
|
|
}
|
|
|
|
void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPointer& pickResult) {
|
|
// TODO: avatars/HUD?
|
|
auto pointerManager = DependencyManager::get<PointerManager>();
|
|
|
|
// NOTE: After this loop: _prevButtons = buttons that were removed
|
|
// If switching to disabled or should stop triggering, release all buttons
|
|
Buttons buttons;
|
|
Buttons newButtons;
|
|
Buttons sameButtons;
|
|
if (_enabled && shouldTrigger(pickResult)) {
|
|
buttons = getPressedButtons(pickResult);
|
|
for (const std::string& button : buttons) {
|
|
if (_prevButtons.find(button) == _prevButtons.end()) {
|
|
newButtons.insert(button);
|
|
} else {
|
|
sameButtons.insert(button);
|
|
_prevButtons.erase(button);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hover events
|
|
bool doHover = shouldHover(pickResult);
|
|
Pointer::PickedObject hoveredObject = getHoveredObject(pickResult);
|
|
PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult);
|
|
hoveredEvent.setType(PointerEvent::Move);
|
|
hoveredEvent.setID(pointerID);
|
|
bool moveOnHoverLeave = (!_enabled && _prevEnabled) || (!doHover && _prevDoHover);
|
|
hoveredEvent.setMoveOnHoverLeave(moveOnHoverLeave);
|
|
|
|
// if shouldHover && !_prevDoHover, only send hoverBegin
|
|
if (_enabled && _hover && doHover && !_prevDoHover) {
|
|
if (hoveredObject.type == ENTITY) {
|
|
emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent);
|
|
} else if (hoveredObject.type == OVERLAY) {
|
|
emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent);
|
|
} else if (hoveredObject.type == HUD) {
|
|
emit pointerManager->hoverBeginHUD(hoveredEvent);
|
|
}
|
|
} else if (_enabled && _hover && doHover) {
|
|
if (hoveredObject.type == OVERLAY) {
|
|
if (_prevHoveredObject.type == OVERLAY) {
|
|
if (hoveredObject.objectID == _prevHoveredObject.objectID) {
|
|
emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent);
|
|
} else {
|
|
PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult);
|
|
prevHoveredEvent.setID(pointerID);
|
|
prevHoveredEvent.setMoveOnHoverLeave(moveOnHoverLeave);
|
|
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent);
|
|
emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent);
|
|
}
|
|
} else {
|
|
emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent);
|
|
if (_prevHoveredObject.type == ENTITY) {
|
|
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == HUD) {
|
|
emit pointerManager->hoverEndHUD(hoveredEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: this is basically repeated code. is there a way to clean it up?
|
|
if (hoveredObject.type == ENTITY) {
|
|
if (_prevHoveredObject.type == ENTITY) {
|
|
if (hoveredObject.objectID == _prevHoveredObject.objectID) {
|
|
emit pointerManager->hoverContinueEntity(hoveredObject.objectID, hoveredEvent);
|
|
} else {
|
|
PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult);
|
|
prevHoveredEvent.setID(pointerID);
|
|
prevHoveredEvent.setMoveOnHoverLeave(moveOnHoverLeave);
|
|
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent);
|
|
emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent);
|
|
}
|
|
} else {
|
|
emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent);
|
|
if (_prevHoveredObject.type == OVERLAY) {
|
|
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == HUD) {
|
|
emit pointerManager->hoverEndHUD(hoveredEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hoveredObject.type == HUD) {
|
|
if (_prevHoveredObject.type == HUD) {
|
|
// There's only one HUD
|
|
emit pointerManager->hoverContinueHUD(hoveredEvent);
|
|
} else {
|
|
emit pointerManager->hoverBeginHUD(hoveredEvent);
|
|
if (_prevHoveredObject.type == ENTITY) {
|
|
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == OVERLAY) {
|
|
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hoveredObject.type == NONE) {
|
|
if (_prevHoveredObject.type == ENTITY) {
|
|
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == OVERLAY) {
|
|
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == HUD) {
|
|
emit pointerManager->hoverEndHUD(hoveredEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Trigger begin
|
|
const std::string SHOULD_FOCUS_BUTTON = "Focus";
|
|
for (const std::string& button : newButtons) {
|
|
hoveredEvent.setType(PointerEvent::Press);
|
|
hoveredEvent.setButton(chooseButton(button));
|
|
hoveredEvent.setShouldFocus(button == SHOULD_FOCUS_BUTTON);
|
|
if (hoveredObject.type == ENTITY) {
|
|
emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent);
|
|
} else if (hoveredObject.type == OVERLAY) {
|
|
emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent);
|
|
} else if (hoveredObject.type == HUD) {
|
|
emit pointerManager->triggerBeginHUD(hoveredEvent);
|
|
}
|
|
_triggeredObjects[button] = hoveredObject;
|
|
}
|
|
|
|
// Trigger continue
|
|
for (const std::string& button : sameButtons) {
|
|
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, button, false);
|
|
triggeredEvent.setID(pointerID);
|
|
triggeredEvent.setType(PointerEvent::Move);
|
|
triggeredEvent.setButton(chooseButton(button));
|
|
if (_triggeredObjects[button].type == ENTITY) {
|
|
emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent);
|
|
} else if (_triggeredObjects[button].type == OVERLAY) {
|
|
emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent);
|
|
} else if (_triggeredObjects[button].type == HUD) {
|
|
emit pointerManager->triggerContinueHUD(triggeredEvent);
|
|
}
|
|
}
|
|
|
|
// Trigger end
|
|
for (const std::string& button : _prevButtons) {
|
|
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, button, false);
|
|
triggeredEvent.setID(pointerID);
|
|
triggeredEvent.setType(PointerEvent::Release);
|
|
triggeredEvent.setButton(chooseButton(button));
|
|
if (_triggeredObjects[button].type == ENTITY) {
|
|
emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent);
|
|
} else if (_triggeredObjects[button].type == OVERLAY) {
|
|
emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent);
|
|
} else if (_triggeredObjects[button].type == HUD) {
|
|
emit pointerManager->triggerEndHUD(triggeredEvent);
|
|
}
|
|
_triggeredObjects.erase(button);
|
|
}
|
|
|
|
// if we disable the pointer or disable hovering, send hoverEnd events after triggerEnd
|
|
if (_hover && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) {
|
|
if (_prevHoveredObject.type == ENTITY) {
|
|
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == OVERLAY) {
|
|
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
|
} else if (_prevHoveredObject.type == HUD) {
|
|
emit pointerManager->hoverEndHUD(hoveredEvent);
|
|
}
|
|
}
|
|
|
|
_prevHoveredObject = hoveredObject;
|
|
_prevButtons = buttons;
|
|
_prevEnabled = _enabled;
|
|
_prevDoHover = doHover;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|