Work In Progress snapshot

* Added new PointerEvent type.
* Mouse events are still sent from Application to EntityTreeRenderer, however, EntityTreeRenderer converts them to PointerEvents
* All outgoing signals from EntityTreeRenderer use PointerEvents instead of MouseEvents
* Associated JavaScript entity methods will receive PointerEvents instead of MouseEvents
* Events from handControllerGrab.js to entities are currently broken.
This commit is contained in:
Anthony J. Thibault 2016-08-12 17:11:59 -07:00
parent 1ddbd7022a
commit 1be434342b
14 changed files with 476 additions and 286 deletions

View file

@ -1074,7 +1074,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
[this](const EntityItemID& entityItemID, const MouseEvent& event) {
[this](const EntityItemID& entityItemID, const PointerEvent& event) {
setKeyboardFocusEntity(entityItemID);
});
@ -1085,9 +1085,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
});
// If the user clicks somewhere where there is NO entity at all, we will release focus
connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity,
[=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event) {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, [=]() {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
});
connect(this, &Application::aboutToQuit, [=]() {
@ -3578,76 +3577,6 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) {
}
}
void Application::sendEntityMouseMoveEvent(QUuid id, glm::vec3 intersectionPoint) {
QMouseEvent mouseEvent(QEvent::MouseMove, QPoint(0, 0), QPoint(0, 0),
Qt::NoButton, Qt::NoButton, Qt::NoModifier);
sendEntityMouseEvent(id, mouseEvent, intersectionPoint);
}
void Application::sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersectionPoint) {
QMouseEvent mouseEvent(QEvent::MouseButtonPress, QPoint(0, 0), QPoint(0, 0),
Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
sendEntityMouseEvent(id, mouseEvent, intersectionPoint);
}
void Application::sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint) {
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, QPoint(0, 0), QPoint(0, 0),
Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
sendEntityMouseEvent(id, mouseEvent, intersectionPoint);
}
void Application::sendEntityMouseEvent(const QUuid& id, const QMouseEvent& mouseEvent, const glm::vec3& intersectionPoint) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityItemID entityItemID(id);
auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (EntityTypes::Web == properties.getType() && !properties.getLocked() && properties.getVisible()) {
auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID);
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
webEntity->handleMouseEvent(mouseEvent, intersectionPoint);
}
}
void Application::sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
QTouchEvent::TouchPoint point;
point.setId(fingerID);
point.setState(Qt::TouchPointMoved);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent touchEvent(QEvent::TouchUpdate, nullptr, Qt::NoModifier, Qt::TouchPointMoved, touchPoints);
sendEntityTouchEvent(entityID, touchEvent, intersectionPoint);
}
void Application::sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
QTouchEvent::TouchPoint point;
point.setId(fingerID);
point.setState(Qt::TouchPointPressed);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent touchEvent(QEvent::TouchBegin, nullptr, Qt::NoModifier, Qt::TouchPointPressed, touchPoints);
sendEntityTouchEvent(entityID, touchEvent, intersectionPoint);
}
void Application::sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
QTouchEvent::TouchPoint point;
point.setId(fingerID);
point.setState(Qt::TouchPointReleased);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent touchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
sendEntityTouchEvent(entityID, touchEvent, intersectionPoint);
}
void Application::sendEntityTouchEvent(const QUuid& id, const QTouchEvent& touchEvent, const glm::vec3& intersectionPoint) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityItemID entityItemID(id);
auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (EntityTypes::Web == properties.getType() && !properties.getLocked() && properties.getVisible()) {
auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID);
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
webEntity->handleTouchEvent(touchEvent, intersectionPoint);
}
}
void Application::updateDialogs(float deltaTime) const {
PerformanceTimer perfTimer("updateDialogs");
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);

View file

@ -325,17 +325,6 @@ public slots:
QUuid getKeyboardFocusEntity() const; // thread-safe
void setKeyboardFocusEntity(QUuid id);
void setKeyboardFocusEntity(EntityItemID entityItemID);
void sendEntityMouseMoveEvent(QUuid id, glm::vec3 intersectionPoint);
void sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersectionPoint);
void sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint);
void sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
void sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
void sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
private:
void sendEntityTouchEvent(const QUuid& id, const QTouchEvent& touchEvent, const glm::vec3& intersectionPoint);
void sendEntityMouseEvent(const QUuid& id, const QMouseEvent& mouseEvent, const glm::vec3& intersectionPoint);
private slots:
void showDesktop();

View file

@ -48,7 +48,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
OctreeRenderer(),
_wantScripts(wantScripts),
_entitiesScriptEngine(NULL),
_lastMouseEventValid(false),
_lastPointerEventValid(false),
_viewState(viewState),
_scriptingServices(scriptingServices),
_displayModelBounds(false),
@ -190,9 +190,9 @@ void EntityTreeRenderer::update() {
// Even if we're not moving the mouse, if we started clicking on an entity and we have
// not yet released the hold then this is still considered a holdingClickOnEntity event
// and we want to simulate this message here as well as in mouse move
if (_lastMouseEventValid && !_currentClickingOnEntityID.isInvalidID()) {
emit holdingClickOnEntity(_currentClickingOnEntityID, _lastMouseEvent);
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", _lastMouseEvent);
if (_lastPointerEventValid && !_currentClickingOnEntityID.isInvalidID()) {
emit holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent);
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", _lastPointerEvent);
}
}
@ -608,18 +608,10 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
}
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface,
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event){
entityScriptingInterface->mousePressOnEntity(intersection.entityID, MouseEvent(*event));
});
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface,
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) {
entityScriptingInterface->mouseMoveOnEntity(intersection.entityID, MouseEvent(*event));
});
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface,
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) {
entityScriptingInterface->mouseReleaseOnEntity(intersection.entityID, MouseEvent(*event));
});
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
connect(this, &EntityTreeRenderer::clickDownOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity);
connect(this, &EntityTreeRenderer::holdingClickOnEntity, entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity);
@ -636,6 +628,59 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS
connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityRenderStatus, Qt::QueuedConnection);
}
static glm::vec2 projectOntoEntityXYPlane(EntityItemPointer entity, const PickRay& pickRay, const RayToEntityIntersectionResult& rayPickResult) {
if (entity) {
glm::vec3 entityPosition = entity->getPosition();
glm::quat entityRotation = entity->getRotation();
glm::vec3 entityDimensions = entity->getDimensions();
glm::vec3 entityRegistrationPoint = entity->getRegistrationPoint();
// project the intersection point onto the local xy plane of the object.
float distance;
glm::vec3 planePosition = entityPosition;
glm::vec3 planeNormal = entityRotation * Vectors::UNIT_Z;
glm::vec3 rayDirection = pickRay.direction;
glm::vec3 rayStart = pickRay.origin;
glm::vec3 p;
if (rayPlaneIntersection(planePosition, planeNormal, rayStart, rayDirection, distance)) {
p = rayStart + rayDirection * distance;
} else {
p = rayPickResult.intersection;
}
glm::vec3 localP = glm::inverse(entityRotation) * (p - entityPosition);
glm::vec3 normalizedP = (localP / entityDimensions) + entityRegistrationPoint;
return glm::vec2(normalizedP.x * entityDimensions.x,
(1.0f - normalizedP.y) * entityDimensions.y); // flip y-axis
} else {
return glm::vec2();
}
}
static uint32_t toPointerButtons(const QMouseEvent& event) {
uint32_t buttons = 0;
buttons |= event.buttons().testFlag(Qt::LeftButton) ? PointerEvent::PrimaryButton : 0;
buttons |= event.buttons().testFlag(Qt::RightButton) ? PointerEvent::SecondaryButton : 0;
buttons |= event.buttons().testFlag(Qt::MiddleButton) ? PointerEvent::TertiaryButton : 0;
return buttons;
}
static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
switch (event.button()) {
case Qt::LeftButton:
return PointerEvent::PrimaryButton;
case Qt::RightButton:
return PointerEvent::SecondaryButton;
case Qt::MiddleButton:
return PointerEvent::TertiaryButton;
default:
return PointerEvent::NoButtons;
}
}
static const uint32_t MOUSE_POINTER_ID = 0;
void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
// If we don't have a tree, or we're in the process of shutting down, then don't
// process these events.
@ -654,24 +699,32 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
QUrl url = QUrl(urlString, QUrl::StrictMode);
if (url.isValid() && !url.isEmpty()){
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
}
emit mousePressOnEntity(rayPickResult, event);
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit mousePressOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", pointerEvent);
}
_currentClickingOnEntityID = rayPickResult.entityID;
emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", pointerEvent);
}
_lastPointerEvent = pointerEvent;
_lastPointerEventValid = true;
} else {
emit mousePressOffEntity(rayPickResult, event);
emit mousePressOffEntity();
}
_lastMouseEvent = MouseEvent(*event);
_lastMouseEventValid = true;
}
void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
@ -680,31 +733,48 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
if (!_tree || _shuttingDown) {
return;
}
PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent");
PickRay ray = _viewState->computePickRay(event->x(), event->y());
bool precisionPicking = !_dontDoPrecisionPicking;
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
if (rayPickResult.intersects) {
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
emit mouseReleaseOnEntity(rayPickResult, event);
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", pointerEvent);
}
_lastPointerEvent = pointerEvent;
_lastPointerEventValid = true;
}
// Even if we're no longer intersecting with an entity, if we started clicking on it, and now
// we're releasing the button, then this is considered a clickOn event
if (!_currentClickingOnEntityID.isInvalidID()) {
emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
auto entity = getTree()->findEntityByID(_currentClickingOnEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", pointerEvent);
}
}
// makes it the unknown ID, we just released so we can't be clicking on anything
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
_lastMouseEvent = MouseEvent(*event);
_lastMouseEventValid = true;
}
void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
@ -721,19 +791,35 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
if (rayPickResult.intersects) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit mouseMoveOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", pointerEvent);
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", pointerEvent);
}
// handle the hover logic...
// if we were previously hovering over an entity, and this new entity is not the same as our previous entity
// then we need to send the hover leave.
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
auto entity = getTree()->findEntityByID(_currentHoverOverEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent);
}
}
@ -741,28 +827,39 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
// this is true if the _currentHoverOverEntityID is known or unknown
if (rayPickResult.entityID != _currentHoverOverEntityID) {
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", pointerEvent);
}
}
// and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and
// we should send our hover over event
emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event));
emit hoverOverEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", pointerEvent);
}
// remember what we're hovering over
_currentHoverOverEntityID = rayPickResult.entityID;
_lastPointerEvent = pointerEvent;
_lastPointerEventValid = true;
} else {
// handle the hover logic...
// if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to
// send the hover leave for our previous entity
if (!_currentHoverOverEntityID.isInvalidID()) {
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
auto entity = getTree()->findEntityByID(_currentHoverOverEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent);
}
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
}
@ -771,13 +868,19 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
// Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have
// not yet released the hold then this is still considered a holdingClickOnEntity event
if (!_currentClickingOnEntityID.isInvalidID()) {
emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
auto entity = getTree()->findEntityByID(_currentClickingOnEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
emit holdingClickOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event));
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", pointerEvent);
}
}
_lastMouseEvent = MouseEvent(*event);
_lastMouseEventValid = true;
}
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {

View file

@ -18,7 +18,8 @@
#include <AbstractAudioInterface.h>
#include <EntityScriptingInterface.h> // for RayToEntityIntersectionResult
#include <EntityTree.h>
#include <MouseEvent.h>
#include <QMouseEvent>
#include <PointerEvent.h>
#include <OctreeRenderer.h>
#include <ScriptCache.h>
#include <TextureCache.h>
@ -98,18 +99,18 @@ public:
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
signals:
void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event);
void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event);
void mouseMoveOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event);
void mouseReleaseOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event);
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mousePressOffEntity();
void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void clickReleaseOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void clickReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void hoverEnterEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void hoverOverEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void hoverLeaveEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void hoverEnterEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void hoverOverEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void hoverLeaveEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void enterEntity(const EntityItemID& entityItemID);
void leaveEntity(const EntityItemID& entityItemID);
@ -174,8 +175,8 @@ private:
void playEntityCollisionSound(const QUuid& myNodeID, EntityTreePointer entityTree,
const EntityItemID& id, const Collision& collision);
bool _lastMouseEventValid;
MouseEvent _lastMouseEvent;
bool _lastPointerEventValid;
PointerEvent _lastPointerEvent;
AbstractViewStateInterface* _viewState;
AbstractScriptingServicesInterface* _scriptingServices;
bool _displayModelBounds;

View file

@ -73,22 +73,27 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
// Restore the original GL context
currentContext->makeCurrent(currentSurface);
auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) {
if (intersection.entityID == getID()) {
handleMouseEvent(*event, intersection.intersection);
auto forwardPointerEvent = [=](const EntityItemID& entityItemID, const PointerEvent& event) {
if (entityItemID == getID()) {
handlePointerEvent(event);
}
};
_mousePressConnection = QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent);
_mouseReleaseConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent);
_mouseMoveConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent);
_hoverLeaveConnection = QObject::connect(renderer, &EntityTreeRenderer::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) {
_mousePressConnection = QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardPointerEvent);
_mouseReleaseConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardPointerEvent);
_mouseMoveConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardPointerEvent);
_hoverLeaveConnection = QObject::connect(renderer, &EntityTreeRenderer::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const PointerEvent& event) {
if (this->_pressed && this->getID() == entityItemID) {
// If the user mouses off the entity while the button is down, simulate a mouse release
QMouseEvent mappedEvent(QEvent::MouseButtonRelease,
QPoint(_lastMove.x, _lastMove.y),
Qt::MouseButton::LeftButton,
Qt::MouseButtons(), Qt::KeyboardModifiers());
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
// If the user mouses off the entity while the button is down, simulate a touch end.
QTouchEvent::TouchPoint point;
point.setId(event.getID());
point.setState(Qt::TouchPointReleased);
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * DPI);
QPointF windowPoint(windowPos.x, windowPos.y);
point.setPos(windowPoint);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent touchEvent = QTouchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
}
});
return true;
@ -173,111 +178,73 @@ QObject* RenderableWebEntityItem::getEventHandler() {
return _webSurface->getEventHandler();
}
void RenderableWebEntityItem::handleMouseEvent(QMouseEvent event, glm::vec3 intersectionPoint) {
void RenderableWebEntityItem::handlePointerEvent(const PointerEvent& event) {
// Ignore mouse interaction if we're locked
if (getLocked()) {
if (getLocked() || !_webSurface) {
return;
}
if (event.button() == Qt::MouseButton::RightButton) {
if (event.type() == QEvent::MouseButtonPress) {
_lastPress = toGlm(event.pos());
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * DPI);
QPointF windowPoint(windowPos.x, windowPos.y);
/*
qDebug() << "AJT: RenderableWebEntityItem::handlePointerEvent!";
qDebug() << "AJT: type = " << (int)event.getType();
qDebug() << "AJT: id = " << event.getID();
qDebug() << "AJT: pos2D = " << event.getPos2D();
qDebug() << "AJT: pos3D = " << event.getPos3D();
qDebug() << "AJT: normal = " << event.getNormal();
qDebug() << "AJT: direction = " << event.getDirection();
qDebug() << "AJT: button = " << (int)event.getButton();
qDebug() << "AJT: buttons = " << event.getButtons();
qDebug() << "AJT: windowPos = " << windowPos;
*/
if (event.getType() == PointerEvent::Move && event.getButtons() == PointerEvent::NoButtons) {
// Forward a mouse move event to webSurface
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
} else {
// Forward a touch update event to webSurface
QEvent::Type type;
Qt::TouchPointState touchPointState;
switch (event.getType()) {
case PointerEvent::Press:
type = QEvent::TouchBegin;
touchPointState = Qt::TouchPointPressed;
break;
case PointerEvent::Release:
type = QEvent::TouchEnd;
touchPointState = Qt::TouchPointReleased;
break;
case PointerEvent::Move:
default:
type = QEvent::TouchUpdate;
touchPointState = Qt::TouchPointMoved;
break;
}
}
if (event.button() == Qt::MouseButton::RightButton) {
if (event.type() == QEvent::MouseButtonRelease) {
ivec2 dist = glm::abs(toGlm(event.pos()) - _lastPress);
if (!glm::any(glm::greaterThan(dist, ivec2(1)))) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack");
});
}
_lastPress = ivec2(INT_MIN);
}
return;
}
QTouchEvent::TouchPoint point;
point.setId(event.getID());
point.setState(touchPointState);
point.setPos(windowPoint);
point.setScreenPos(windowPoint);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
// FIXME doesn't work... double click events not received
if (event.type() == QEvent::MouseButtonDblClick) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
_webSurface->getRootItem()->setProperty("url", _sourceUrl);
});
}
QTouchEvent touchEvent(type, nullptr, Qt::NoModifier, touchPointState, touchPoints);
QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
if (event.button() == Qt::MouseButton::MiddleButton) {
if (event.type() == QEvent::MouseButtonRelease) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
_webSurface->getRootItem()->setProperty("url", _sourceUrl);
});
}
return;
_lastTouchEvent = touchEvent;
}
// Map the intersection point to an actual offscreen pixel
glm::vec3 point = intersectionPoint;
glm::vec3 dimensions = getDimensions();
point -= getPosition();
point = glm::inverse(getRotation()) * point;
point /= dimensions;
point += 0.5f;
point.y = 1.0f - point.y;
point *= dimensions * (METERS_TO_INCHES * DPI);
if (event.button() == Qt::MouseButton::LeftButton) {
if (event.type() == QEvent::MouseButtonPress) {
_pressed = true;
_lastMove = ivec2((int)point.x, (int)point.y);
} else if (event.type() == QEvent::MouseButtonRelease) {
_pressed = false;
}
}
if (event.type() == QEvent::MouseMove) {
_lastMove = ivec2((int)point.x, (int)point.y);
}
// Forward the mouse event.
QMouseEvent mappedEvent(event.type(),
QPoint((int)point.x, (int)point.y),
event.screenPos(), event.button(),
event.buttons(), event.modifiers());
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
}
void RenderableWebEntityItem::handleTouchEvent(QTouchEvent event, glm::vec3 intersectionPoint) {
// Ignore mouse interaction if we're locked
if (getLocked()) {
return;
}
// Map the intersection point to an actual offscreen pixel
glm::vec3 point = intersectionPoint;
glm::vec3 dimensions = getDimensions();
point -= getPosition();
point = glm::inverse(getRotation()) * point;
point /= dimensions;
point += 0.5f;
point.y = 1.0f - point.y;
point *= dimensions * (METERS_TO_INCHES * DPI);
QList<QTouchEvent::TouchPoint> touchPoints = event.touchPoints();
for (auto& touchPoint : touchPoints) {
touchPoint.setPos(QPointF(point.x, point.y));
touchPoint.setScreenPos(QPointF(point.x, point.y));
}
// Forward the touch event.
QTouchEvent mappedEvent(event.type(),
event.device(),
event.modifiers(),
event.touchPointStates(),
touchPoints);
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
}
void RenderableWebEntityItem::destroyWebSurface() {
if (_webSurface) {
qDebug() << "AJT: destroyWebSurface!";
--_currentWebCount;
_webSurface->pause();
_webSurface->disconnect(_connection);

View file

@ -11,6 +11,8 @@
#include <QSharedPointer>
#include <QMouseEvent>
#include <QTouchEvent>
#include <PointerEvent.h>
#include <WebEntityItem.h>
@ -33,8 +35,7 @@ public:
void setProxyWindow(QWindow* proxyWindow);
QObject* getEventHandler();
void handleMouseEvent(QMouseEvent event, glm::vec3 intersectionPoint);
void handleTouchEvent(QTouchEvent event, glm::vec3 intersectionPoint);
void handlePointerEvent(const PointerEvent& event);
void update(const quint64& now) override;
bool needsToCallUpdate() const override { return _webSurface != nullptr; }
@ -50,7 +51,7 @@ private:
uint32_t _texture{ 0 };
ivec2 _lastPress{ INT_MIN };
bool _pressed{ false };
ivec2 _lastMove{ INT_MIN };
QTouchEvent _lastTouchEvent { QEvent::TouchUpdate };
uint64_t _lastRenderTime{ 0 };
QMetaObject::Connection _mousePressConnection;

View file

@ -1195,27 +1195,33 @@ void EntityScriptingInterface::setKeyboardFocusEntity(QUuid id) {
}
void EntityScriptingInterface::sendEntityMouseMoveEvent(QUuid id, glm::vec3 intersectionPoint) {
QMetaObject::invokeMethod(qApp, "sendEntityMouseMoveEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
// AJT: TODO CURRENTLY BROKEN
//QMetaObject::invokeMethod(qApp, "sendEntityMouseMoveEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
}
void EntityScriptingInterface::sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersectionPoint) {
QMetaObject::invokeMethod(qApp, "sendEntityLeftMouseDownEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
// AJT: TODO CURRENTLY BROKEN
//QMetaObject::invokeMethod(qApp, "sendEntityLeftMouseDownEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
}
void EntityScriptingInterface::sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint) {
QMetaObject::invokeMethod(qApp, "sendEntityLeftMouseUpEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
// AJT: TODO CURRENTLY BROKEN
//QMetaObject::invokeMethod(qApp, "sendEntityLeftMouseUpEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
}
void EntityScriptingInterface::sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
QMetaObject::invokeMethod(qApp, "sendEntityTouchUpdateEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
// AJT: TODO CURRENTLY BROKEN
//QMetaObject::invokeMethod(qApp, "sendEntityTouchUpdateEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
}
void EntityScriptingInterface::sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
QMetaObject::invokeMethod(qApp, "sendEntityTouchBeginEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
// AJT: TODO CURRENTLY BROKEN
//QMetaObject::invokeMethod(qApp, "sendEntityTouchBeginEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
}
void EntityScriptingInterface::sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
QMetaObject::invokeMethod(qApp, "sendEntityTouchEndEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
// AJT: TODO CURRENTLY BROKEN
//QMetaObject::invokeMethod(qApp, "sendEntityTouchEndEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
}
float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) {

View file

@ -34,7 +34,7 @@
#include "EntityItemProperties.h"
class EntityTree;
class MouseEvent;
class PointerEvent;
class RayToEntityIntersectionResult {
public:
@ -181,10 +181,10 @@ public slots:
Q_INVOKABLE QUuid getKeyboardFocusEntity() const;
Q_INVOKABLE void setKeyboardFocusEntity(QUuid id);
// AJT: TODO CURRENTLY BROKEN
Q_INVOKABLE void sendEntityMouseMoveEvent(QUuid id, glm::vec3 intersectionPoint);
Q_INVOKABLE void sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersectionPoint);
Q_INVOKABLE void sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint);
Q_INVOKABLE void sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
Q_INVOKABLE void sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
Q_INVOKABLE void sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
@ -197,17 +197,17 @@ signals:
void canRezChanged(bool canRez);
void canRezTmpChanged(bool canRez);
void mousePressOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mouseMoveOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void clickReleaseOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void clickReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void hoverEnterEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void hoverOverEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void hoverLeaveEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void hoverEnterEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void hoverOverEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void hoverLeaveEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void enterEntity(const EntityItemID& entityItemID);
void leaveEntity(const EntityItemID& entityItemID);

View file

@ -13,6 +13,7 @@
#include "KeyEvent.h"
#include "MouseEvent.h"
#include "SpatialEvent.h"
#include "PointerEvent.h"
#include "TouchEvent.h"
#include "WheelEvent.h"
@ -22,6 +23,7 @@ void registerEventTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, HFActionEvent::toScriptValue, HFActionEvent::fromScriptValue);
qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue);
qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue);
qScriptRegisterMetaType(engine, PointerEvent::toScriptValue, PointerEvent::fromScriptValue);
qScriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue);
qScriptRegisterMetaType(engine, WheelEvent::toScriptValue, WheelEvent::fromScriptValue);
qScriptRegisterMetaType(engine, SpatialEvent::toScriptValue, SpatialEvent::fromScriptValue);

View file

@ -0,0 +1,110 @@
//
// PointerEvent.cpp
// script-engine/src
//
// Created by Anthony Thibault on 2016-8-11.
// Copyright 2016 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 <qscriptengine.h>
#include <qscriptvalue.h>
#include "PointerEvent.h"
static bool areFlagsSet(uint32_t flags, uint32_t mask) {
return (flags & mask) != 0;
}
PointerEvent::PointerEvent() {
;
}
PointerEvent::PointerEvent(EventType type, uint32_t id,
const glm::vec2& pos2D, const glm::vec3& pos3D,
const glm::vec3& normal, const glm::vec3& direction,
Button button, uint32_t buttons) :
_type(type),
_id(id),
_pos2D(pos2D),
_pos3D(pos3D),
_normal(normal),
_direction(direction),
_button(button),
_buttons(buttons)
{
;
}
QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEvent& event) {
QScriptValue obj = engine->newObject();
switch (event._type) {
case Press:
obj.setProperty("type", "Press");
break;
case Release:
obj.setProperty("type", "Release");
break;
default:
case Move:
obj.setProperty("type", "Move");
break;
};
obj.setProperty("id", event._id);
QScriptValue pos2D = engine->newObject();
pos2D.setProperty("x", event._pos2D.x);
pos2D.setProperty("y", event._pos2D.y);
obj.setProperty("pos2D", pos2D);
QScriptValue pos3D = engine->newObject();
pos3D.setProperty("x", event._pos3D.x);
pos3D.setProperty("y", event._pos3D.y);
pos3D.setProperty("z", event._pos3D.z);
obj.setProperty("pos3D", pos3D);
QScriptValue normal = engine->newObject();
normal.setProperty("x", event._normal.x);
normal.setProperty("y", event._normal.y);
normal.setProperty("z", event._normal.z);
obj.setProperty("pos3D", normal);
QScriptValue direction = engine->newObject();
direction.setProperty("x", event._direction.x);
direction.setProperty("y", event._direction.y);
direction.setProperty("z", event._direction.z);
obj.setProperty("pos3D", direction);
switch (event._button) {
case NoButtons:
obj.setProperty("button", "None");
break;
case PrimaryButton:
obj.setProperty("button", "Primary");
break;
case SecondaryButton:
obj.setProperty("button", "Secondary");
break;
case TertiaryButton:
obj.setProperty("button", "Tertiary");
break;
}
obj.setProperty("isLeftButton", areFlagsSet(event._buttons, PrimaryButton));
obj.setProperty("isRightButton", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isMiddleButton", areFlagsSet(event._buttons, TertiaryButton));
obj.setProperty("isPrimaryButton", areFlagsSet(event._buttons, PrimaryButton));
obj.setProperty("isSecondaryButton", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isTertiaryButton", areFlagsSet(event._buttons, TertiaryButton));
return obj;
}
void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& event) {
// nothing for now...
}

View file

@ -0,0 +1,68 @@
//
// PointerEvent.h
// script-engine/src
//
// Created by Anthony Thibault on 2016-8-11.
// Copyright 2016 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_PointerEvent_h
#define hifi_PointerEvent_h
#include <stdint.h>
#include <glm/glm.hpp>
#include <QScriptValue>
class PointerEvent {
public:
enum Button {
NoButtons = 0x0,
PrimaryButton = 0x1,
SecondaryButton = 0x2,
TertiaryButton = 0x4
};
enum EventType {
Press, // A button has just been pressed
Release, // A button has just been released
Move // The pointer has just moved
};
PointerEvent();
PointerEvent(EventType type, uint32_t id,
const glm::vec2& pos2D, const glm::vec3& pos3D,
const glm::vec3& normal, const glm::vec3& direction,
Button button, uint32_t buttons);
static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event);
static void fromScriptValue(const QScriptValue& object, PointerEvent& event);
QScriptValue toScriptValue(QScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); }
EventType getType() const { return _type; }
uint32_t getID() const { return _id; }
const glm::vec2& getPos2D() const { return _pos2D; }
const glm::vec3& getPos3D() const { return _pos3D; }
const glm::vec3& getNormal() const { return _normal; }
const glm::vec3& getDirection() const { return _direction; }
Button getButton() const { return _button; }
uint32_t getButtons() const { return _buttons; }
private:
EventType _type;
uint32_t _id; // used to identify the pointer. (left vs right hand, for example)
glm::vec2 _pos2D; // (in meters) projected onto the xy plane of entities dimension box, (0, 0) is upper right hand corner
glm::vec3 _pos3D; // surface location in world coordinates (in meters)
glm::vec3 _normal; // surface normal
glm::vec3 _direction; // incoming direction of pointer ray.
Button _button { NoButtons }; // button assosiated with this event, (if type is Press, this will be the button that is pressed)
uint32_t _buttons { NoButtons }; // the current state of all the buttons.
};
Q_DECLARE_METATYPE(PointerEvent)
#endif // hifi_PointerEvent_h

View file

@ -723,9 +723,9 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
};
};
using MouseHandler = std::function<void(const EntityItemID&, const MouseEvent&)>;
auto makeMouseHandler = [this](QString eventName) -> MouseHandler {
return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) {
using PointerHandler = std::function<void(const EntityItemID&, const PointerEvent&)>;
auto makePointerHandler = [this](QString eventName) -> PointerHandler {
return [this, eventName](const EntityItemID& entityItemID, const PointerEvent& event) {
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) });
};
};
@ -741,17 +741,17 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity"));
connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity"));
connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity"));
connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makePointerHandler("mousePressOnEntity"));
connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makePointerHandler("mouseMoveOnEntity"));
connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makePointerHandler("mouseReleaseOnEntity"));
connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity"));
connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity"));
connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity"));
connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makePointerHandler("clickDownOnEntity"));
connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makePointerHandler("holdingClickOnEntity"));
connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makePointerHandler("clickReleaseOnEntity"));
connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity"));
connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));
connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));
connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makePointerHandler("hoverEnterEntity"));
connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makePointerHandler("hoverOverEntity"));
connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makePointerHandler("hoverLeaveEntity"));
connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity"));
}
@ -1546,7 +1546,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
}
}
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event) {
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
@ -1556,12 +1556,12 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
Q_ARG(const EntityItemID&, entityID),
Q_ARG(const QString&, methodName),
Q_ARG(const MouseEvent&, event));
Q_ARG(const PointerEvent&, event));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
"entityID:" << entityID << "methodName:" << methodName << "event: pointerEvent";
#endif
refreshFileScript(entityID);

View file

@ -30,7 +30,7 @@
#include <EntityItemID.h>
#include <EntitiesScriptEngineProvider.h>
#include "MouseEvent.h"
#include "PointerEvent.h"
#include "ArrayBufferClass.h"
#include "AssetScriptingInterface.h"
#include "AudioScriptingInterface.h"
@ -139,7 +139,7 @@ public:
Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID); // will call unload method
Q_INVOKABLE void unloadAllEntityScripts();
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params = QStringList());
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event);
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event);
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision);
Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); }

View file

@ -113,6 +113,20 @@ int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk)
// calculate the angle between a point on a sphere that is closest to the cone.
float coneSphereAngle(const glm::vec3& coneCenter, const glm::vec3& coneDirection, const glm::vec3& sphereCenter, float sphereRadius);
inline bool rayPlaneIntersection(const glm::vec3& planePosition, const glm::vec3& planeNormal,
const glm::vec3& rayStart, const glm::vec3& rayDirection, float& distanceOut) {
float rayDirectionDotPlaneNormal = glm::dot(rayDirection, planeNormal);
const float PARALLEL_THRESHOLD = 0.0001f;
if (fabsf(rayDirectionDotPlaneNormal) > PARALLEL_THRESHOLD) {
float rayStartDotPlaneNormal = glm::dot(planePosition - rayStart, planeNormal);
distanceOut = rayStartDotPlaneNormal / rayDirectionDotPlaneNormal;
return true;
} else {
// ray is parallel to the plane
return false;
}
}
typedef glm::vec2 LineSegment2[2];
// Polygon Clipping routines inspired by, pseudo code found here: http://www.cs.rit.edu/~icss571/clipTrans/PolyClipBack.html