Merge branch 'master' of https://github.com/highfidelity/hifi into stagingSetting

This commit is contained in:
Zach Fox 2017-10-26 13:58:50 -07:00
commit 3e95484c4c
32 changed files with 321 additions and 638 deletions

View file

@ -22,8 +22,7 @@ RowLayout {
property var sample: null;
property bool isPlaying: false;
function createSampleSound() {
var SOUND = Qt.resolvedUrl("../../../sounds/sample.wav");
sound = SoundCache.getSound(SOUND);
sound = ApplicationInterface.getSampleSound();
sample = null;
}
function playSound() {

View file

@ -691,7 +691,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<CloseEventSender>();
DependencyManager::set<ResourceManager>();
DependencyManager::set<SelectionScriptingInterface>();
DependencyManager::set<ContextOverlayInterface>();
DependencyManager::set<Ledger>();
DependencyManager::set<Wallet>();
DependencyManager::set<WalletScriptingInterface>();
@ -759,7 +758,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_notifiedPacketVersionMismatchThisDomain(false),
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
_lastFaceTrackerUpdate(0),
_snapshotSound(nullptr)
_snapshotSound(nullptr),
_sampleSound(nullptr)
{
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
@ -804,7 +805,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
installNativeEventFilter(&MyNativeEventFilter::getInstance());
#endif
_logger = new FileLogger(this);
qInstallMessageHandler(messageHandler);
@ -981,6 +981,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(myAvatar.get(), &MyAvatar::positionGoneTo,
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
// Inititalize sample before registering
QFileInfo infSample = QFileInfo(PathUtils::resourcesPath() + "sounds/sample.wav");
_sampleSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSample.absoluteFilePath()));
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
registerScriptEngineWithApplicationServices(engine);
@ -1182,7 +1186,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// allow you to move an entity around in your hand
_entityEditSender.setPacketsPerSecond(3000); // super high!!
// Overlays need to exist before we set the ContextOverlayInterface dependency
_overlays.init(); // do this before scripts load
DependencyManager::set<ContextOverlayInterface>();
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
@ -1472,53 +1479,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
});
// If the user clicks somewhere where there is NO entity at all, we will release focus
connect(getEntities().data(), &EntityTreeRenderer::mousePressOffEntity, [=]() {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
});
// Keyboard focus handling for Web overlays.
auto overlays = &(qApp->getOverlays());
connect(overlays, &Overlays::mousePressOnOverlay, [=](const OverlayID& overlayID, const PointerEvent& event) {
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays->getOverlay(overlayID));
// Only Web overlays can have keyboard focus.
if (thisOverlay) {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusOverlay(overlayID);
}
});
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
if (overlayID == _keyboardFocusedOverlay.get()) {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
}
});
connect(overlays, &Overlays::mousePressOffOverlay, [=]() {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
});
connect(this, &Application::aboutToQuit, [=]() {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
});
connect(overlays,
SIGNAL(mousePressOnOverlay(const OverlayID&, const PointerEvent&)),
DependencyManager::get<ContextOverlayInterface>().data(),
SLOT(contextOverlays_mousePressOnOverlay(const OverlayID&, const PointerEvent&)));
connect(overlays,
SIGNAL(hoverEnterOverlay(const OverlayID&, const PointerEvent&)),
DependencyManager::get<ContextOverlayInterface>().data(),
SLOT(contextOverlays_hoverEnterOverlay(const OverlayID&, const PointerEvent&)));
connect(overlays,
SIGNAL(hoverLeaveOverlay(const OverlayID&, const PointerEvent&)),
DependencyManager::get<ContextOverlayInterface>().data(),
SLOT(contextOverlays_hoverLeaveOverlay(const OverlayID&, const PointerEvent&)));
// Add periodic checks to send user activity data
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
static int NEARBY_AVATAR_RADIUS_METERS = 10;
@ -1787,9 +1760,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return entityServerNode && !isPhysicsEnabled();
});
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(inf.absoluteFilePath()));
QFileInfo infSnap = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSnap.absoluteFilePath()));
QVariant testProperty = property(hifi::properties::TEST);
qDebug() << testProperty;
if (testProperty.isValid()) {
@ -4202,6 +4175,7 @@ void Application::initDisplay() {
}
void Application::init() {
// Make sure Login state is up to date
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
@ -4554,14 +4528,9 @@ QUuid Application::getKeyboardFocusEntity() const {
return _keyboardFocusedEntity.get();
}
void Application::setKeyboardFocusEntity(QUuid id) {
EntityItemID entityItemID(id);
setKeyboardFocusEntity(entityItemID);
}
static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
void Application::setKeyboardFocusEntity(EntityItemID entityItemID) {
void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
if (_keyboardFocusedEntity.get() != entityItemID) {
_keyboardFocusedEntity.set(entityItemID);
@ -4598,7 +4567,7 @@ OverlayID Application::getKeyboardFocusOverlay() {
return _keyboardFocusedOverlay.get();
}
void Application::setKeyboardFocusOverlay(OverlayID overlayID) {
void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) {
if (overlayID != _keyboardFocusedOverlay.get()) {
_keyboardFocusedOverlay.set(overlayID);
@ -6810,6 +6779,10 @@ void Application::loadScriptURLDialog() const {
});
}
SharedSoundPointer Application::getSampleSound() const {
return _sampleSound;
}
void Application::loadLODToolsDialog() {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET));
@ -7432,51 +7405,6 @@ bool Application::isForeground() const {
return _isForeground && !_window->isMinimized();
}
void Application::sendMousePressOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->mousePressOnEntity(entityItemID, event);
}
void Application::sendMouseMoveOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->mouseMoveOnEntity(entityItemID, event);
}
void Application::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->mouseReleaseOnEntity(entityItemID, event);
}
void Application::sendClickDownOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->clickDownOnEntity(entityItemID, event);
}
void Application::sendHoldingClickOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->holdingClickOnEntity(entityItemID, event);
}
void Application::sendClickReleaseOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->clickReleaseOnEntity(entityItemID, event);
}
void Application::sendHoverEnterEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverEnterEntity(entityItemID, event);
}
void Application::sendHoverOverEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverOverEntity(entityItemID, event);
}
void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverLeaveEntity(entityItemID, event);
}
// FIXME? perhaps two, one for the main thread and one for the offscreen UI rendering thread?
static const int UI_RESERVED_THREADS = 1;
// Windows won't let you have all the cores

View file

@ -277,18 +277,6 @@ public:
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event);
OverlayID getTabletScreenID() const;
OverlayID getTabletHomeButtonID() const;
QUuid getTabletFrameID() const; // may be an entity or an overlay
@ -326,6 +314,7 @@ public slots:
void toggleEntityScriptServerLogDialog();
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
Q_INVOKABLE void loadAddAvatarBookmarkDialog() const;
Q_INVOKABLE SharedSoundPointer getSampleSound() const;
void showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const;
@ -388,11 +377,10 @@ public slots:
void setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions);
QUuid getKeyboardFocusEntity() const; // thread-safe
void setKeyboardFocusEntity(QUuid id);
void setKeyboardFocusEntity(EntityItemID entityItemID);
void setKeyboardFocusEntity(const EntityItemID& entityItemID);
OverlayID getKeyboardFocusOverlay();
void setKeyboardFocusOverlay(OverlayID overlayID);
void setKeyboardFocusOverlay(const OverlayID& overlayID);
void addAssetToWorldMessageClose();
@ -702,6 +690,7 @@ private:
FileScriptingInterface* _fileDownload;
AudioInjectorPointer _snapshotSoundInjector;
SharedSoundPointer _snapshotSound;
SharedSoundPointer _sampleSound;
DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin;
QString _autoSwitchDisplayModeSupportedHMDPluginName;

View file

@ -43,10 +43,10 @@ ContextOverlayInterface::ContextOverlayInterface() {
_entityPropertyFlags += PROP_REGISTRATION_POINT;
_entityPropertyFlags += PROP_CERTIFICATE_ID;
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>().data();
connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&)));
connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&)));
connect(entityTreeRenderer, SIGNAL(hoverLeaveEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverLeaveEntity(const EntityItemID&, const PointerEvent&)));
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay);
connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity);
connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity);
connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() {
if (_contextOverlayJustClicked && _hmdScriptingInterface->isMounted()) {
QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID();
@ -59,9 +59,12 @@ ContextOverlayInterface::ContextOverlayInterface() {
_contextOverlayJustClicked = false;
}
});
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity);
connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay);
connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay);
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged);
}

View file

@ -717,39 +717,34 @@ bool Overlays::isAddedOverlay(OverlayID id) {
}
void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
QMetaObject::invokeMethod(this, "mousePressOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
mousePressEvent(overlayID, event);
}
void Overlays::sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
QMetaObject::invokeMethod(this, "mouseReleaseOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
mouseReleaseEvent(overlayID, event);
}
void Overlays::sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
QMetaObject::invokeMethod(this, "mouseMoveOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
mouseMoveEvent(overlayID, event);
}
void Overlays::sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event) {
QMetaObject::invokeMethod(this, "hoverEnterOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
void Overlays::sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event) {
emit hoverEnterOverlay(overlayID, event);
}
void Overlays::sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event) {
QMetaObject::invokeMethod(this, "hoverOverOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) {
emit hoverOverOverlay(overlayID, event);
}
void Overlays::sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event) {
QMetaObject::invokeMethod(this, "hoverLeaveOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
void Overlays::sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) {
hoverLeaveEvent(overlayID, event);
}
OverlayID Overlays::getKeyboardFocusOverlay() {
return qApp->getKeyboardFocusOverlay();
}
void Overlays::setKeyboardFocusOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setKeyboardFocusOverlay", Q_ARG(OverlayID, id));
return;
}
void Overlays::setKeyboardFocusOverlay(const OverlayID& id) {
qApp->setKeyboardFocusOverlay(id);
}
@ -884,13 +879,35 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
_currentClickingOnOverlayID = rayPickResult.overlayID;
PointerEvent pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
mousePressEvent(_currentClickingOnOverlayID, pointerEvent);
return true;
}
// if we didn't press on an overlay, disable overlay keyboard focus
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
// emit to scripts
emit mousePressOffOverlay();
return false;
}
void Overlays::mousePressEvent(const OverlayID& overlayID, const PointerEvent& event) {
// TODO: generalize this to allow any overlay to recieve events
std::shared_ptr<Web3DOverlay> thisOverlay;
if (getOverlayType(overlayID) == "web3d") {
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
}
if (thisOverlay) {
// Focus keyboard on web overlays
DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusOverlay(overlayID);
// Send to web overlay
QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
}
// emit to scripts
emit mousePressOnOverlay(overlayID, event);
}
bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
@ -900,13 +917,30 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
_currentClickingOnOverlayID = rayPickResult.overlayID;
auto pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
// emit to scripts
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
return true;
}
// emit to scripts
emit mouseDoublePressOffOverlay();
return false;
}
void Overlays::hoverLeaveEvent(const OverlayID& overlayID, const PointerEvent& event) {
// TODO: generalize this to allow any overlay to recieve events
std::shared_ptr<Web3DOverlay> thisOverlay;
if (getOverlayType(overlayID) == "web3d") {
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
}
if (thisOverlay) {
// Send to web overlay
QMetaObject::invokeMethod(thisOverlay.get(), "hoverLeaveOverlay", Q_ARG(PointerEvent, event));
}
// emit to scripts
emit hoverLeaveOverlay(overlayID, event);
}
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
@ -914,13 +948,28 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
if (rayPickResult.intersects) {
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
emit mouseReleaseOnOverlay(rayPickResult.overlayID, pointerEvent);
mouseReleaseEvent(rayPickResult.overlayID, pointerEvent);
}
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
return false;
}
void Overlays::mouseReleaseEvent(const OverlayID& overlayID, const PointerEvent& event) {
// TODO: generalize this to allow any overlay to recieve events
std::shared_ptr<Web3DOverlay> thisOverlay;
if (getOverlayType(overlayID) == "web3d") {
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
}
if (thisOverlay) {
// Send to web overlay
QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
}
// emit to scripts
emit mouseReleaseOnOverlay(overlayID, event);
}
bool Overlays::mouseMoveEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
@ -928,12 +977,12 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
if (rayPickResult.intersects) {
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
emit mouseMoveOnOverlay(rayPickResult.overlayID, pointerEvent);
mouseMoveEvent(rayPickResult.overlayID, pointerEvent);
// If previously hovering over a different overlay then leave hover on that overlay.
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) {
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
hoverLeaveEvent(_currentHoverOverOverlayID, pointerEvent);
}
// If hovering over a new overlay then enter hover on that overlay.
@ -949,7 +998,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
// If previously hovering an overlay then leave hover.
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID) {
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
hoverLeaveEvent(_currentHoverOverOverlayID, pointerEvent);
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
}
@ -957,6 +1006,21 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
return false;
}
void Overlays::mouseMoveEvent(const OverlayID& overlayID, const PointerEvent& event) {
// TODO: generalize this to allow any overlay to recieve events
std::shared_ptr<Web3DOverlay> thisOverlay;
if (getOverlayType(overlayID) == "web3d") {
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
}
if (thisOverlay) {
// Send to web overlay
QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
}
// emit to scripts
emit mouseMoveOnOverlay(overlayID, event);
}
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
QVector<QUuid> result;
//if (QThread::currentThread() != thread()) {

View file

@ -107,6 +107,11 @@ public:
bool mouseReleaseEvent(QMouseEvent* event);
bool mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(const OverlayID& overlayID, const PointerEvent& event);
void mouseMoveEvent(const OverlayID& overlayID, const PointerEvent& event);
void mouseReleaseEvent(const OverlayID& overlayID, const PointerEvent& event);
void hoverLeaveEvent(const OverlayID& overlayID, const PointerEvent& event);
void cleanupAllOverlays();
public slots:
@ -298,12 +303,12 @@ public slots:
void sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event);
void sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event);
void sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event);
void sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event);
void sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event);
OverlayID getKeyboardFocusOverlay();
void setKeyboardFocusOverlay(OverlayID id);
void setKeyboardFocusOverlay(const OverlayID& id);
signals:
/**jsdoc

View file

@ -125,11 +125,7 @@ void Web3DOverlay::destroyWebSurface() {
}
_webSurface->pause();
auto overlays = &(qApp->getOverlays());
QObject::disconnect(overlays, &Overlays::mousePressOnOverlay, this, nullptr);
QObject::disconnect(overlays, &Overlays::mouseReleaseOnOverlay, this, nullptr);
QObject::disconnect(overlays, &Overlays::mouseMoveOnOverlay, this, nullptr);
QObject::disconnect(overlays, &Overlays::hoverLeaveOverlay, this, nullptr);
QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
DependencyManager::get<OffscreenQmlSurfaceCache>()->release(QML, _webSurface);
@ -160,35 +156,17 @@ void Web3DOverlay::buildWebSurface() {
_webSurface->resume();
});
auto selfOverlayID = getOverlayID();
std::weak_ptr<Web3DOverlay> weakSelf = std::dynamic_pointer_cast<Web3DOverlay>(qApp->getOverlays().getOverlay(selfOverlayID));
auto forwardPointerEvent = [=](OverlayID overlayID, const PointerEvent& event) {
auto self = weakSelf.lock();
if (self && overlayID == selfOverlayID) {
self->handlePointerEvent(event);
}
};
auto overlays = &(qApp->getOverlays());
QObject::connect(overlays, &Overlays::mousePressOnOverlay, this, forwardPointerEvent);
QObject::connect(overlays, &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent);
QObject::connect(overlays, &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent);
QObject::connect(overlays, &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) {
auto self = weakSelf.lock();
if (!self) {
return;
}
if (overlayID == selfOverlayID && (self->_pressed || (!self->_activeTouchPoints.empty() && self->_touchBeginAccepted))) {
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
forwardPointerEvent(overlayID, endEvent);
}
});
QObject::connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
}
void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) {
if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted))) {
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
handlePointerEvent(endEvent);
}
}
void Web3DOverlay::update(float deltatime) {
if (_webSurface) {

View file

@ -39,7 +39,8 @@ public:
QObject* getEventHandler();
void setProxyWindow(QWindow* proxyWindow);
void handlePointerEvent(const PointerEvent& event);
Q_INVOKABLE void hoverLeaveOverlay(const PointerEvent& event);
Q_INVOKABLE void handlePointerEvent(const PointerEvent& event);
void handlePointerEventAsTouch(const PointerEvent& event);
void handlePointerEventAsMouse(const PointerEvent& event);

View file

@ -23,7 +23,6 @@ class SoundCache : public ResourceCache, public Dependency {
public:
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
protected:
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
const void* extra) override;

View file

@ -35,6 +35,8 @@
#include "EntitiesRendererLogging.h"
#include "RenderableEntityItem.h"
#include "RenderableWebEntityItem.h"
size_t std::hash<EntityItemID>::operator()(const EntityItemID& id) const { return qHash(id); }
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction;
@ -55,6 +57,32 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
EntityRenderer::initEntityRenderers();
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
// Forward mouse events to web entities
auto handlePointerEvent = [&](const EntityItemID& entityID, const PointerEvent& event) {
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
auto entity = getEntity(entityID);
if (entity && entity->getType() == EntityTypes::Web) {
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
}
if (thisEntity) {
QMetaObject::invokeMethod(thisEntity.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
}
};
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent);
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent);
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent);
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const EntityItemID& entityID, const PointerEvent& event) {
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
auto entity = getEntity(entityID);
if (entity && entity->getType() == EntityTypes::Web) {
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
}
if (thisEntity) {
QMetaObject::invokeMethod(thisEntity.get(), "hoverLeaveEntity", Q_ARG(PointerEvent, event));
}
});
}
EntityTreeRenderer::~EntityTreeRenderer() {
@ -78,13 +106,49 @@ render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& i
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
void EntityTreeRenderer::resetEntitiesScriptEngine() {
auto oldEngine = _entitiesScriptEngine;
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
_entitiesScriptEngine->runInThread();
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(entitiesScriptEngineProvider);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
entityScriptingInterface->setEntitiesScriptEngine(entitiesScriptEngineProvider);
// Connect mouse events to entity script callbacks
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mousePressOnEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseDoublePressOnEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseMoveOnEntity", event);
// FIXME: this is a duplicate of mouseMoveOnEntity, but it seems like some scripts might use this naming
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseMoveEvent", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseReleaseOnEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "clickDownOnEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "holdingClickOnEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "clickReleaseOnEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverEnterEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverOverEntity", event);
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverLeaveEntity", event);
});
}
void EntityTreeRenderer::clear() {
@ -264,8 +328,7 @@ void EntityTreeRenderer::update(bool simulate) {
// 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 (_lastPointerEventValid && !_currentClickingOnEntityID.isInvalidID()) {
emit holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent);
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", _lastPointerEvent);
emit DependencyManager::get<EntityScriptingInterface>()->holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent);
}
}
@ -435,19 +498,6 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha
}
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
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);
connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity);
connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity);
@ -516,13 +566,11 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
}
PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent");
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
PickRay ray = _viewState->computePickRay(event->x(), event->y());
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
if (rayPickResult.intersects) {
//qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID;
auto entity = getTree()->findEntityByEntityItemID(rayPickResult.entityID);
auto properties = entity->getProperties();
if (rayPickResult.intersects && rayPickResult.entity) {
auto properties = rayPickResult.entity->getProperties();
QString urlString = properties.getHref();
QUrl url = QUrl(urlString, QUrl::StrictMode);
if (url.isValid() && !url.isEmpty()){
@ -536,23 +584,16 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit mousePressOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", pointerEvent);
}
emit entityScriptingInterface->mousePressOnEntity(rayPickResult.entityID, pointerEvent);
_currentClickingOnEntityID = rayPickResult.entityID;
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", pointerEvent);
}
emit entityScriptingInterface->clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
_lastPointerEvent = pointerEvent;
_lastPointerEventValid = true;
} else {
emit mousePressOffEntity();
emit entityScriptingInterface->mousePressOffEntity();
}
}
@ -564,34 +605,25 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
}
PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent");
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
PickRay ray = _viewState->computePickRay(event->x(), event->y());
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
if (rayPickResult.intersects) {
//qCDebug(entitiesrenderer) << "mouseDoublePressEvent over entity:" << rayPickResult.entityID;
if (rayPickResult.intersects && rayPickResult.entity) {
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), Qt::NoModifier);
emit mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseDoublePressOnEntity", pointerEvent);
}
emit entityScriptingInterface->mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
_currentClickingOnEntityID = rayPickResult.entityID;
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "doubleclickOnEntity", pointerEvent);
}
emit entityScriptingInterface->clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
_lastPointerEvent = pointerEvent;
_lastPointerEventValid = true;
} else {
emit mouseDoublePressOffEntity();
emit entityScriptingInterface->mouseDoublePressOffEntity();
}
}
@ -603,9 +635,10 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
}
PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent");
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
PickRay ray = _viewState->computePickRay(event->x(), event->y());
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
if (rayPickResult.intersects) {
if (rayPickResult.intersects && rayPickResult.entity) {
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
@ -615,31 +648,23 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", pointerEvent);
}
emit entityScriptingInterface->mouseReleaseOnEntity(rayPickResult.entityID, 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
// we're releasing the button, then this is considered a clickReleaseOn event
if (!_currentClickingOnEntityID.isInvalidID()) {
auto entity = getTree()->findEntityByID(_currentClickingOnEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
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),
Qt::NoModifier); // TODO -- check for modifier keys?
emit clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", pointerEvent);
}
emit entityScriptingInterface->clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
}
// makes it the unknown ID, we just released so we can't be clicking on anything
@ -654,9 +679,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
}
PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent");
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
PickRay ray = _viewState->computePickRay(event->x(), event->y());
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
if (rayPickResult.intersects) {
if (rayPickResult.intersects && rayPickResult.entity) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
@ -664,48 +690,32 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit mouseMoveOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", pointerEvent);
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", pointerEvent);
}
emit entityScriptingInterface->mouseMoveOnEntity(rayPickResult.entityID, 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) {
auto entity = getTree()->findEntityByID(_currentHoverOverEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
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),
Qt::NoModifier); // TODO -- check for modifier keys?
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent);
}
emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
}
// If the new hover entity does not match the previous hover entity then we are entering the new one
// this is true if the _currentHoverOverEntityID is known or unknown
if (rayPickResult.entityID != _currentHoverOverEntityID) {
emit hoverEnterEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", pointerEvent);
}
emit entityScriptingInterface->hoverEnterEntity(rayPickResult.entityID, 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, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", pointerEvent);
}
emit entityScriptingInterface->hoverOverEntity(rayPickResult.entityID, pointerEvent);
// remember what we're hovering over
_currentHoverOverEntityID = rayPickResult.entityID;
@ -718,38 +728,18 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
// 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()) {
auto entity = getTree()->findEntityByID(_currentHoverOverEntityID);
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
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),
Qt::NoModifier); // TODO -- check for modifier keys?
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent);
}
emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
}
}
// 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()) {
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),
Qt::NoModifier); // TODO -- check for modifier keys?
emit holdingClickOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", pointerEvent);
_lastPointerEvent = pointerEvent;
_lastPointerEventValid = true;
}
}
}

View file

@ -117,21 +117,6 @@ public:
void onEntityChanged(const EntityItemID& id);
signals:
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseDoublePressOnEntity(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 mouseDoublePressOffEntity();
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 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);
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);

View file

@ -24,7 +24,6 @@
#include <ui/TabletScriptingInterface.h>
#include <EntityScriptingInterface.h>
#include "EntityTreeRenderer.h"
#include "EntitiesRendererLogging.h"
@ -86,6 +85,10 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
return true;
}
if (_lastLocked != entity->getLocked()) {
return true;
}
return false;
}
@ -136,6 +139,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
}
_lastDPI = entity->getDPI();
_lastLocked = entity->getLocked();
glm::vec2 windowSize = getWindowSize(entity);
_webSurface->resize(QSize(windowSize.x, windowSize.y));
@ -234,38 +238,6 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
emit entities->webEventReceived(entityItemID, message);
});
auto forwardPointerEvent = [=](const EntityItemID& entityItemID, const PointerEvent& event) {
if (entityItemID == entity->getID()) {
handlePointerEvent(entity, event);
}
};
auto renderer = DependencyManager::get<EntityTreeRenderer>();
QObject::connect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, this, forwardPointerEvent);
QObject::connect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, this, forwardPointerEvent);
QObject::connect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, this, forwardPointerEvent);
QObject::connect(renderer.data(), &EntityTreeRenderer::hoverLeaveEntity, this,
[=](const EntityItemID& entityItemID, const PointerEvent& event) {
if (this->_pressed && entity->getID() == entityItemID) {
// 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 * _lastDPI);
QPointF windowPoint(windowPos.x, windowPos.y);
point.setScenePos(windowPoint);
point.setPos(windowPoint);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr,
Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
touchEvent->setWindow(_webSurface->getWindow());
touchEvent->setDevice(&_touchDevice);
touchEvent->setTarget(_webSurface->getRootItem());
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
}
});
return true;
}
@ -295,13 +267,6 @@ void WebEntityRenderer::destroyWebSurface() {
}
webSurface->pause();
auto renderer = DependencyManager::get<EntityTreeRenderer>();
if (renderer) {
QObject::disconnect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, this, nullptr);
QObject::disconnect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, this, nullptr);
QObject::disconnect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, this, nullptr);
QObject::disconnect(renderer.data(), &EntityTreeRenderer::hoverLeaveEntity, this, nullptr);
}
webSurface.reset();
}
}
@ -347,13 +312,34 @@ void WebEntityRenderer::loadSourceURL() {
}
}
void WebEntityRenderer::handlePointerEvent(const TypedEntityPointer& entity, const PointerEvent& event) {
void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) {
if (!_lastLocked && _webSurface && _pressed) {
// 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 * _lastDPI);
QPointF windowPoint(windowPos.x, windowPos.y);
point.setScenePos(windowPoint);
point.setPos(windowPoint);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr,
Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
touchEvent->setWindow(_webSurface->getWindow());
touchEvent->setDevice(&_touchDevice);
touchEvent->setTarget(_webSurface->getRootItem());
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
}
}
void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) {
// Ignore mouse interaction if we're locked
if (entity->getLocked() || !_webSurface) {
if (_lastLocked || !_webSurface) {
return;
}
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * entity->getDPI());
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI);
QPointF windowPoint(windowPos.x, windowPos.y);
if (event.getType() == PointerEvent::Move) {
// Forward a mouse move event to webSurface

View file

@ -18,12 +18,16 @@ class PointerEvent;
namespace render { namespace entities {
class WebEntityRenderer : public TypedEntityRenderer<WebEntityItem> {
Q_OBJECT
using Parent = TypedEntityRenderer<WebEntityItem>;
friend class EntityRenderer;
public:
WebEntityRenderer(const EntityItemPointer& entity);
Q_INVOKABLE void hoverLeaveEntity(const PointerEvent& event);
Q_INVOKABLE void handlePointerEvent(const PointerEvent& event);
protected:
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
virtual bool needsRenderUpdate() const override;
@ -44,9 +48,6 @@ private:
bool hasWebSurface();
void loadSourceURL();
glm::vec2 getWindowSize(const TypedEntityPointer& entity) const;
void handlePointerEvent(const TypedEntityPointer& entity, const PointerEvent& event);
private:
int _geometryId{ 0 };
enum contentType {
@ -60,6 +61,7 @@ private:
bool _pressed{ false };
QString _lastSourceUrl;
uint16_t _lastDPI;
bool _lastLocked;
QTimer _timer;
uint64_t _lastRenderTime { 0 };
Transform _renderTransform;

View file

@ -51,6 +51,10 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged);
connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);
// If the user clicks somewhere where there is no entity at all, we will release focus
connect(this, &EntityScriptingInterface::mousePressOffEntity, [=]() {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
});
auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket");
@ -1674,44 +1678,44 @@ QUuid EntityScriptingInterface::getKeyboardFocusEntity() const {
return result;
}
void EntityScriptingInterface::setKeyboardFocusEntity(QUuid id) {
QMetaObject::invokeMethod(qApp, "setKeyboardFocusEntity", Qt::QueuedConnection, Q_ARG(QUuid, id));
void EntityScriptingInterface::setKeyboardFocusEntity(const EntityItemID& id) {
QMetaObject::invokeMethod(qApp, "setKeyboardFocusEntity", Qt::DirectConnection, Q_ARG(EntityItemID, id));
}
void EntityScriptingInterface::sendMousePressOnEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendMousePressOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event) {
emit mousePressOnEntity(id, event);
}
void EntityScriptingInterface::sendMouseMoveOnEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendMouseMoveOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event) {
emit mouseMoveOnEntity(id, event);
}
void EntityScriptingInterface::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendMouseReleaseOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event) {
emit mouseReleaseOnEntity(id, event);
}
void EntityScriptingInterface::sendClickDownOnEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendClickDownOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event) {
emit clickDownOnEntity(id, event);
}
void EntityScriptingInterface::sendHoldingClickOnEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendHoldingClickOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event) {
emit holdingClickOnEntity(id, event);
}
void EntityScriptingInterface::sendClickReleaseOnEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendClickReleaseOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event) {
emit clickReleaseOnEntity(id, event);
}
void EntityScriptingInterface::sendHoverEnterEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendHoverEnterEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event) {
emit hoverEnterEntity(id, event);
}
void EntityScriptingInterface::sendHoverOverEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendHoverOverEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event) {
emit hoverOverEntity(id, event);
}
void EntityScriptingInterface::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
QMetaObject::invokeMethod(qApp, "sendHoverLeaveEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
void EntityScriptingInterface::sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event) {
emit hoverLeaveEntity(id, event);
}
bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) {

View file

@ -380,19 +380,19 @@ public slots:
Q_INVOKABLE QString getNestableType(QUuid id);
Q_INVOKABLE QUuid getKeyboardFocusEntity() const;
Q_INVOKABLE void setKeyboardFocusEntity(QUuid id);
Q_INVOKABLE void setKeyboardFocusEntity(const EntityItemID& id);
Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE void sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event);
Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id);
@ -439,8 +439,11 @@ signals:
void canWriteAssetsChanged(bool canWriteAssets);
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseDoublePressOnEntity(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 mouseDoublePressOffEntity();
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);

View file

@ -511,12 +511,19 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
auto keyLight = lightAndShadow.first;
model::LightPointer keyAmbientLight;
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
keyAmbientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front());
}
bool hasAmbientMap = (keyAmbientLight != nullptr);
// Setup the global directional pass pipeline
{
if (deferredLightingEffect->_shadowMapEnabled) {
// If the keylight has an ambient Map then use the Skybox version of the pass
// otherwise use the ambient sphere version
if (keyLight->getAmbientMap()) {
if (hasAmbientMap) {
program = deferredLightingEffect->_directionalSkyboxLightShadow;
locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations;
} else {
@ -526,7 +533,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
} else {
// If the keylight has an ambient Map then use the Skybox version of the pass
// otherwise use the ambient sphere version
if (keyLight->getAmbientMap()) {
if (hasAmbientMap) {
program = deferredLightingEffect->_directionalSkyboxLight;
locations = deferredLightingEffect->_directionalSkyboxLightLocations;
} else {

View file

@ -138,7 +138,7 @@ void main(void) {
}
// Mix with background at far range
const float BLEND_DISTANCE = 30000.0;
const float BLEND_DISTANCE = 27000.0;
if (distance > BLEND_DISTANCE) {
outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlendValue);
} else {

View file

@ -97,7 +97,6 @@ static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true };
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
int functionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature>();
Q_DECLARE_METATYPE(ScriptEnginePointer)
int scriptEnginePointerMetaID = qRegisterMetaType<ScriptEnginePointer>();
Q_LOGGING_CATEGORY(scriptengineScript, "hifi.scriptengine.script")

View file

@ -55,6 +55,8 @@ static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900;
class ScriptEngines;
Q_DECLARE_METATYPE(ScriptEnginePointer)
class CallbackData {
public:
QScriptValue function;

View file

@ -119,6 +119,7 @@ Script.include("/~/system/libraries/controllers.js");
this.actionID = null; // action this script created...
this.entityWithContextOverlay = false;
this.contextOverlayTimer = false;
this.previousCollisionStatus = false;
this.reticleMinX = MARGIN;
this.reticleMaxX;
this.reticleMinY = MARGIN;
@ -342,7 +343,9 @@ Script.include("/~/system/libraries/controllers.js");
if (this.madeDynamic) {
var props = {};
props.dynamic = false;
props.collisionless = this.previousCollisionStatus;
props.localVelocity = {x: 0, y: 0, z: 0};
props.localRotation = {x: 0, y: 0, z: 0};
Entities.editEntity(this.grabbedThingID, props);
this.madeDynamic = false;
}
@ -507,10 +510,12 @@ Script.include("/~/system/libraries/controllers.js");
if (entityIsGrabbable(targetProps)) {
if (!entityIsDistanceGrabbable(targetProps)) {
targetProps.dynamic = true;
this.previousCollisionStatus = targetProps.collisionless;
targetProps.collisionless = true;
Entities.editEntity(entityID, targetProps);
this.madeDynamic = true;
}
if (!this.distanceRotating) {
this.grabbedThingID = entityID;
this.grabbedDistance = rayPickInfo.distance;

View file

@ -1373,7 +1373,7 @@ function loaded() {
elShape.addEventListener('change', createEmitTextPropertyUpdateFunction('shape'));
elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl'));
elWebDPI.addEventListener('change', createEmitNumberPropertyUpdateFunction('dpi'));
elWebDPI.addEventListener('change', createEmitNumberPropertyUpdateFunction('dpi', 0));
elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL'));
elShapeType.addEventListener('change', createEmitTextPropertyUpdateFunction('shapeType'));

View file

@ -1,89 +0,0 @@
//
// spawnStopwatch.js
//
// Created by Ryan Huffman on 1/20/17.
// 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
//
var forward = Quat.getFront(MyAvatar.orientation);
Vec3.print("Forward: ", forward);
var positionToSpawn = Vec3.sum(MyAvatar.position, Vec3.multiply(3, forward));
var scale = 0.5;
positionToSpawn.y += 0.5;
var stopwatchID = Entities.addEntity({
type: "Model",
name: "stopwatch/base",
position: positionToSpawn,
modelURL: Script.resolvePath("models/Stopwatch.fbx"),
dimensions: Vec3.multiply(scale, {"x":4.129462242126465,"y":1.058512806892395,"z":5.773681640625}),
rotation: Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0))
});
var secondHandID = Entities.addEntity({
type: "Model",
name: "stopwatch/seconds",
parentID: stopwatchID,
localPosition: Vec3.multiply(scale, {"x":-0.004985813982784748,"y":0.39391064643859863,"z":0.8312804698944092}),
dimensions: Vec3.multiply(scale, {"x":0.14095762372016907,"y":0.02546107769012451,"z":1.6077008247375488}),
registrationPoint: {"x":0.5,"y":0.5,"z":1},
modelURL: Script.resolvePath("models/Stopwatch-sec-hand.fbx"),
});
var minuteHandID = Entities.addEntity({
type: "Model",
name: "stopwatch/minutes",
parentID: stopwatchID,
localPosition: Vec3.multiply(scale, {"x":-0.0023056098725646734,"y":0.3308190703392029,"z":0.21810021996498108}),
dimensions: Vec3.multiply(scale, {"x":0.045471154153347015,"y":0.015412690117955208,"z":0.22930574417114258}),
registrationPoint: {"x":0.5,"y":0.5,"z":1},
modelURL: Script.resolvePath("models/Stopwatch-min-hand.fbx"),
});
var startStopButtonID = Entities.addEntity({
type: "Model",
name: "stopwatch/startStop",
parentID: stopwatchID,
dimensions: Vec3.multiply(scale, { x: 0.8, y: 0.8, z: 1.0 }),
localPosition: Vec3.multiply(scale, { x: 0, y: -0.1, z: -2.06 }),
modelURL: Script.resolvePath("models/transparent-box.fbx")
});
var resetButtonID = Entities.addEntity({
type: "Model",
name: "stopwatch/startStop",
parentID: stopwatchID,
dimensions: Vec3.multiply(scale, { x: 0.6, y: 0.6, z: 0.8 }),
localPosition: Vec3.multiply(scale, { x: -1.5, y: -0.1, z: -1.2 }),
localRotation: Quat.fromVec3Degrees({ x: 0, y: 36, z: 0 }),
modelURL: Script.resolvePath("models/transparent-box.fbx")
});
Entities.editEntity(stopwatchID, {
userData: JSON.stringify({
secondHandID: secondHandID,
minuteHandID: minuteHandID
}),
serverScripts: Script.resolvePath("stopwatchServer.js")
});
Entities.editEntity(startStopButtonID, {
userData: JSON.stringify({
stopwatchID: stopwatchID,
grabbableKey: { wantsTrigger: true }
}),
script: Script.resolvePath("stopwatchStartStop.js")
});
Entities.editEntity(resetButtonID, {
userData: JSON.stringify({
stopwatchID: stopwatchID,
grabbableKey: { wantsTrigger: true }
}),
script: Script.resolvePath("stopwatchReset.js")
});
Script.stop()

View file

@ -1,22 +0,0 @@
//
// stopwatchReset.js
//
// Created by David Rowe on 26 May 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
//
(function () {
this.preload = function (entityID) {
var properties = Entities.getEntityProperties(entityID, "userData");
this.messageChannel = "STOPWATCH-" + JSON.parse(properties.userData).stopwatchID;
};
function click() {
Messages.sendMessage(this.messageChannel, "reset");
}
this.startNearTrigger = click;
this.startFarTrigger = click;
this.clickDownOnEntity = click;
});

View file

@ -1,132 +0,0 @@
//
// stopwatchServer.js
//
// Created by Ryan Huffman on 1/20/17.
// 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
//
(function() {
var self = this;
self.equipped = false;
self.isActive = false;
self.seconds = 0;
self.secondHandID = null;
self.minuteHandID = null;
self.tickSound = SoundCache.getSound(Script.resolvePath("sounds/tick.wav"));
self.tickInjector = null;
self.tickIntervalID = null;
self.chimeSound = SoundCache.getSound(Script.resolvePath("sounds/chime.wav"));
self.preload = function(entityID) {
print("Preloading stopwatch: ", entityID);
self.entityID = entityID;
self.messageChannel = "STOPWATCH-" + entityID;
var userData = Entities.getEntityProperties(self.entityID, 'userData').userData;
var data = JSON.parse(userData);
self.secondHandID = data.secondHandID;
self.minuteHandID = data.minuteHandID;
self.resetTimer();
Messages.subscribe(self.messageChannel);
Messages.messageReceived.connect(this, self.messageReceived);
};
self.unload = function() {
print("Unloading stopwatch:", self.entityID);
self.resetTimer();
Messages.unsubscribe(self.messageChannel);
Messages.messageReceived.disconnect(this, self.messageReceived);
};
self.messageReceived = function(channel, message, sender) {
print("Message received", channel, sender, message);
if (channel === self.messageChannel) {
switch (message) {
case "startStop":
if (self.isActive) {
self.stopTimer();
} else {
self.startTimer();
}
break;
case "reset":
self.stopTimer();
self.resetTimer();
break;
}
}
};
self.getStopwatchPosition = function() {
return Entities.getEntityProperties(self.entityID, "position").position;
};
self.resetTimer = function() {
print("Resetting stopwatch");
Entities.editEntity(self.secondHandID, {
localRotation: Quat.fromPitchYawRollDegrees(0, 0, 0),
angularVelocity: { x: 0, y: 0, z: 0 },
});
Entities.editEntity(self.minuteHandID, {
localRotation: Quat.fromPitchYawRollDegrees(0, 0, 0),
angularVelocity: { x: 0, y: 0, z: 0 },
});
self.seconds = 0;
};
self.startTimer = function() {
print("Starting stopwatch");
if (!self.tickInjector) {
self.tickInjector = Audio.playSound(self.tickSound, {
position: self.getStopwatchPosition(),
volume: 0.7,
loop: true
});
} else {
self.tickInjector.restart();
}
self.tickIntervalID = Script.setInterval(function() {
if (self.tickInjector) {
self.tickInjector.setOptions({
position: self.getStopwatchPosition(),
volume: 0.7,
loop: true
});
}
self.seconds++;
const degreesPerTick = -360 / 60;
Entities.editEntity(self.secondHandID, {
localRotation: Quat.fromPitchYawRollDegrees(0, self.seconds * degreesPerTick, 0),
});
if (self.seconds % 60 == 0) {
Entities.editEntity(self.minuteHandID, {
localRotation: Quat.fromPitchYawRollDegrees(0, (self.seconds / 60) * degreesPerTick, 0),
});
Audio.playSound(self.chimeSound, {
position: self.getStopwatchPosition(),
volume: 1.0,
loop: false
});
}
}, 1000);
self.isActive = true;
};
self.stopTimer = function () {
print("Stopping stopwatch");
if (self.tickInjector) {
self.tickInjector.stop();
}
if (self.tickIntervalID !== null) {
Script.clearInterval(self.tickIntervalID);
self.tickIntervalID = null;
}
self.isActive = false;
};
});

View file

@ -1,23 +0,0 @@
//
// stopwatchStartStop.js
//
// Created by David Rowe on 26 May 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
//
(function () {
var messageChannel;
this.preload = function (entityID) {
var properties = Entities.getEntityProperties(entityID, "userData");
this.messageChannel = "STOPWATCH-" + JSON.parse(properties.userData).stopwatchID;
};
function click() {
Messages.sendMessage(this.messageChannel, "startStop");
}
this.startNearTrigger = click;
this.startFarTrigger = click;
this.clickDownOnEntity = click;
});