From 642a1e30961e82feb54212e72bae489f6f52a737 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 11 Jul 2017 17:07:53 -0700 Subject: [PATCH 01/95] framework for LaserPointers and abstracted RayPicking on C++ side, including JS API --- interface/src/Application.cpp | 8 +++ .../src/LaserPointerScriptingInterface.cpp | 56 +++++++++++++++++++ .../src/LaserPointerScriptingInterface.h | 33 +++++++++++ .../src/controllers/LaserPointer.cpp | 35 ++++++++++++ .../src/controllers/LaserPointer.h | 34 +++++++++++ .../src/controllers/LaserPointerManager.cpp | 36 ++++++++++++ .../src/controllers/LaserPointerManager.h | 36 ++++++++++++ libraries/shared/src/JointRayPick.cpp | 26 +++++++++ libraries/shared/src/JointRayPick.h | 32 +++++++++++ libraries/shared/src/RayPick.cpp | 18 ++++++ libraries/shared/src/RayPick.h | 42 ++++++++++++++ libraries/shared/src/RayPickManager.cpp | 54 ++++++++++++++++++ libraries/shared/src/RayPickManager.h | 50 +++++++++++++++++ libraries/shared/src/StaticRayPick.cpp | 17 ++++++ libraries/shared/src/StaticRayPick.h | 28 ++++++++++ 15 files changed, 505 insertions(+) create mode 100644 interface/src/LaserPointerScriptingInterface.cpp create mode 100644 interface/src/LaserPointerScriptingInterface.h create mode 100644 libraries/controllers/src/controllers/LaserPointer.cpp create mode 100644 libraries/controllers/src/controllers/LaserPointer.h create mode 100644 libraries/controllers/src/controllers/LaserPointerManager.cpp create mode 100644 libraries/controllers/src/controllers/LaserPointerManager.h create mode 100644 libraries/shared/src/JointRayPick.cpp create mode 100644 libraries/shared/src/JointRayPick.h create mode 100644 libraries/shared/src/RayPick.cpp create mode 100644 libraries/shared/src/RayPick.h create mode 100644 libraries/shared/src/RayPickManager.cpp create mode 100644 libraries/shared/src/RayPickManager.h create mode 100644 libraries/shared/src/StaticRayPick.cpp create mode 100644 libraries/shared/src/StaticRayPick.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ddd1870723..16e322a142 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -190,6 +190,8 @@ #include #include #include +#include "LaserPointerScriptingInterface.h" +#include // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -4916,6 +4918,11 @@ void Application::update(float deltaTime) { _overlays.update(deltaTime); } + { + PROFILE_RANGE(app, "RayPick"); + RayPickManager::getInstance().update(); + } + // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the // loadViewFrumstum() method will get the correct details from the camera @@ -5761,6 +5768,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AvatarBookmarks", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LocationBookmarks", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("LaserPointers", LaserPointerScriptingInterface::getInstance()); // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); diff --git a/interface/src/LaserPointerScriptingInterface.cpp b/interface/src/LaserPointerScriptingInterface.cpp new file mode 100644 index 0000000000..a5770a9252 --- /dev/null +++ b/interface/src/LaserPointerScriptingInterface.cpp @@ -0,0 +1,56 @@ +// +// LaserPointerScriptingInterface.cpp +// interface/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "LaserPointerScriptingInterface.h" + +#include +#include "Transform.h" + +LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { + static LaserPointerScriptingInterface instance; + return &instance; +} + +uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { + QVariantMap propertyMap = properties.toMap(); + + if (propertyMap["joint"].isValid()) { + QString jointName = propertyMap["joint"].toString(); + + Transform offsetTransform; + if (propertyMap["offsetTransform"].isValid()) { + // TODO: + // convert transform + } + + uint16_t filter = 0; + if (propertyMap["filter"].isValid()) { + filter = propertyMap["filter"].toUInt(); + } + + float maxDistance = 0.0f; + if (propertyMap["maxDistance"].isValid()) { + maxDistance = propertyMap["maxDistance"].toFloat(); + } + + bool enabled = false; + if (propertyMap["enabled"].isValid()) { + enabled = propertyMap["enabled"].toBool(); + } + + // TODO: + // handle render state properties + + return LaserPointerManager::getInstance().createLaserPointer(jointName, offsetTransform, filter, maxDistance, enabled); + } else { + return 0; + } +} \ No newline at end of file diff --git a/interface/src/LaserPointerScriptingInterface.h b/interface/src/LaserPointerScriptingInterface.h new file mode 100644 index 0000000000..c455843d03 --- /dev/null +++ b/interface/src/LaserPointerScriptingInterface.h @@ -0,0 +1,33 @@ +// +// LaserPointerScriptingInterface.h +// interface/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_LaserPointerScriptingInterface_h +#define hifi_LaserPointerScriptingInterface_h + +#include + +#include "controllers\LaserPointerManager.h" + +class LaserPointerScriptingInterface : public QObject { + Q_OBJECT + +public: + static LaserPointerScriptingInterface* getInstance(); + +public slots: + Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties); + Q_INVOKABLE void enableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().enableLaserPointer(uid); } + Q_INVOKABLE void disableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().disableLaserPointer(uid); } + Q_INVOKABLE void removeLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().removeLaserPointer(uid); } + //Q_INVOKABLE IntersectionResults getLaserPointerCollisionResults(unsigned int uid) { LaserPointerManager::getInstance().getLaserPointerCollisionResults(uid); } + +}; + +#endif hifi_LaserPointerScriptingInterface_h \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointer.cpp b/libraries/controllers/src/controllers/LaserPointer.cpp new file mode 100644 index 0000000000..4f3adce875 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointer.cpp @@ -0,0 +1,35 @@ +// +// LaserPointer.cpp +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "LaserPointer.h" + +#include "RayPickManager.h" +#include "JointRayPick.h" + +LaserPointer::LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) +{ + _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled)); +} + +LaserPointer::~LaserPointer() { + RayPickManager::getInstance().removeRayPick(_rayPickUID); +} + +void LaserPointer::enable() { + RayPickManager::getInstance().enableRayPick(_rayPickUID); + // TODO: + // turn on rendering +} + +void LaserPointer::disable() { + RayPickManager::getInstance().disableRayPick(_rayPickUID); + // TODO: + // turn off rendering +} \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointer.h b/libraries/controllers/src/controllers/LaserPointer.h new file mode 100644 index 0000000000..d09defe7b2 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointer.h @@ -0,0 +1,34 @@ +// +// LaserPointer.h +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_LaserPointer_h +#define hifi_LaserPointer_h + +#include +#include "Transform.h" + +class LaserPointer { + +public: + LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + ~LaserPointer(); + + unsigned int getUID() { return _rayPickUID; } + void enable(); + void disable(); + + // void setRenderState(const QString& stateName); + // void setRenderStateProperties(const QHash& renderStateProperties); + +private: + unsigned int _rayPickUID; +}; + +#endif hifi_LaserPointer_h \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointerManager.cpp b/libraries/controllers/src/controllers/LaserPointerManager.cpp new file mode 100644 index 0000000000..adea77f530 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointerManager.cpp @@ -0,0 +1,36 @@ +// +// LaserPointerManager.cpp +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "LaserPointerManager.h" +#include "LaserPointer.h" + +LaserPointerManager& LaserPointerManager::getInstance() { + static LaserPointerManager instance; + return instance; +} + +unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled); + unsigned int uid = laserPointer->getUID(); + _laserPointers[uid] = laserPointer; + return uid; +} + +void LaserPointerManager::enableLaserPointer(const unsigned int uid) { + if (_laserPointers.contains(uid)) { + _laserPointers[uid]->enable(); + } +} + +void LaserPointerManager::disableLaserPointer(const unsigned int uid) { + if (_laserPointers.contains(uid)) { + _laserPointers[uid]->disable(); + } +} \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointerManager.h b/libraries/controllers/src/controllers/LaserPointerManager.h new file mode 100644 index 0000000000..28d354cf98 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointerManager.h @@ -0,0 +1,36 @@ +// +// LaserPointerManager.h +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_LaserPointerManager_h +#define hifi_LaserPointerManager_h + +#include +#include +#include +#include "Transform.h" + +class LaserPointer; + +class LaserPointerManager { + +public: + static LaserPointerManager& getInstance(); + + unsigned int createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } + void enableLaserPointer(const unsigned int uid); + void disableLaserPointer(const unsigned int uid); + +private: + QHash> _laserPointers; + +}; + +#endif hifi_LaserPointerManager_h \ No newline at end of file diff --git a/libraries/shared/src/JointRayPick.cpp b/libraries/shared/src/JointRayPick.cpp new file mode 100644 index 0000000000..4a645fa3fd --- /dev/null +++ b/libraries/shared/src/JointRayPick.cpp @@ -0,0 +1,26 @@ +// +// JointRayPick.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "JointRayPick.h" + +JointRayPick::JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) : + RayPick(filter, maxDistance, enabled), + _jointName(jointName), + _offsetTransform(offsetTransform) +{ +} + +const PickRay JointRayPick::getPickRay() { + // TODO: + // get pose for _jointName + // apply _offsetTransform + // create and return PickRay + return PickRay(); +} diff --git a/libraries/shared/src/JointRayPick.h b/libraries/shared/src/JointRayPick.h new file mode 100644 index 0000000000..cd5de79c69 --- /dev/null +++ b/libraries/shared/src/JointRayPick.h @@ -0,0 +1,32 @@ +// +// JointRayPick.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_JointRayPick_h +#define hifi_JointRayPick_h + +#include "RayPick.h" + +#include +#include "Transform.h" + +class JointRayPick : public RayPick { + +public: + JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + + const PickRay getPickRay() override; + +private: + QString _jointName; + Transform _offsetTransform; + +}; + +#endif hifi_JointRayPick_h \ No newline at end of file diff --git a/libraries/shared/src/RayPick.cpp b/libraries/shared/src/RayPick.cpp new file mode 100644 index 0000000000..674913e2e0 --- /dev/null +++ b/libraries/shared/src/RayPick.cpp @@ -0,0 +1,18 @@ +// +// RayPick.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPick.h" + +RayPick::RayPick(const uint16_t filter, const float maxDistance, const bool enabled) : + _filter(filter), + _maxDistance(maxDistance), + _enabled(enabled) +{ +} diff --git a/libraries/shared/src/RayPick.h b/libraries/shared/src/RayPick.h new file mode 100644 index 0000000000..8a292bf5f7 --- /dev/null +++ b/libraries/shared/src/RayPick.h @@ -0,0 +1,42 @@ +// +// RayPick.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPick_h +#define hifi_RayPick_h + +#include +#include "RegisteredMetaTypes.h" + +class RayPick { + +public: + RayPick(const uint16_t filter, const float maxDistance, const bool enabled); + + virtual const PickRay getPickRay() = 0; + + void enable() { _enabled = true; } + void disable() { _enabled = false; } + + const uint16_t getFilter() { return _filter; } + const float getMaxDistance() { return _maxDistance; } + const bool isEnabled() { return _enabled; } + //const IntersectionResult& getLastIntersectionResult() { return _prevIntersectionResult; } + + //void setIntersectionResult(const IntersectionResult& intersectionResult) { _prevIntersectionResult = intersectionResult; } + +private: + uint16_t _filter; + float _maxDistance; + bool _enabled; + //IntersectionResult _prevIntersectionResult; // set to invalid on disable()? + +}; + +#endif hifi_RayPick_h \ No newline at end of file diff --git a/libraries/shared/src/RayPickManager.cpp b/libraries/shared/src/RayPickManager.cpp new file mode 100644 index 0000000000..5c5ebd8c10 --- /dev/null +++ b/libraries/shared/src/RayPickManager.cpp @@ -0,0 +1,54 @@ +// +// RayPickManager.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPickManager.h" +#include "RayPick.h" + +RayPickManager& RayPickManager::getInstance() { + static RayPickManager instance; + return instance; +} + +void RayPickManager::update() { + /*** + - somehow calculate minimum number of intersection tests, update raypicks accordingly + -one option : + loop over all raypicks{ loop over all necessary intersection tests and take min distance less than rayPick->maxDistance, but keep cache of this frame's previous tests to prevent duplicate intersection tests } + ***/ +} + +unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { + // TODO: + // use lock and defer adding to prevent issues + _rayPicks[_nextUID] = rayPick; + return _nextUID++; +} + +void RayPickManager::removeRayPick(const unsigned int uid) { + // TODO: + // use lock and defer removing to prevent issues + _rayPicks.remove(uid); +} + +void RayPickManager::enableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer enabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->enable(); + } +} + +void RayPickManager::disableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer disabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->disable(); + } +} diff --git a/libraries/shared/src/RayPickManager.h b/libraries/shared/src/RayPickManager.h new file mode 100644 index 0000000000..c296c14af7 --- /dev/null +++ b/libraries/shared/src/RayPickManager.h @@ -0,0 +1,50 @@ +// +// RayPickManager.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPickManager_h +#define hifi_RayPickManager_h + +#include +#include + +class RayPick; + +enum RayPickMask { + PICK_NOTHING = 0, + PICK_ENTITIES = 1, + PICK_AVATARS = 2, + PICK_OVERLAYS = 4, + PICK_HUD = 8, + + PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) + + PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements + + PICK_ALL_INTERSECTIONS = 64 // if not set, returns closest intersection, otherwise, returns list of all intersections +}; + +class RayPickManager { + +public: + static RayPickManager& getInstance(); + + void update(); + unsigned int addRayPick(std::shared_ptr rayPick); + void removeRayPick(const unsigned int uid); + void enableRayPick(const unsigned int uid); + void disableRayPick(const unsigned int uid); + +private: + QHash> _rayPicks; + unsigned int _nextUID { 1 }; // 0 is invalid + +}; + +#endif hifi_RayPickManager_h \ No newline at end of file diff --git a/libraries/shared/src/StaticRayPick.cpp b/libraries/shared/src/StaticRayPick.cpp new file mode 100644 index 0000000000..2ebe431b00 --- /dev/null +++ b/libraries/shared/src/StaticRayPick.cpp @@ -0,0 +1,17 @@ +// +// StaticRayPick.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "StaticRayPick.h" + +StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const bool enabled) : + RayPick(filter, maxDistance, enabled), + _pickRay(position, direction) +{ +} diff --git a/libraries/shared/src/StaticRayPick.h b/libraries/shared/src/StaticRayPick.h new file mode 100644 index 0000000000..6424b731c7 --- /dev/null +++ b/libraries/shared/src/StaticRayPick.h @@ -0,0 +1,28 @@ +// +// StaticRayPick.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_StaticRayPick_h +#define hifi_StaticRayPick_h + +#include "RayPick.h" + +class StaticRayPick : public RayPick { + +public: + StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + + const PickRay getPickRay() override { return _pickRay; }; + +private: + PickRay _pickRay; + +}; + +#endif hifi_StaticRayPick_h \ No newline at end of file From 15ec38b30202a7953b4374183524e2da93ae1950 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 12 Jul 2017 14:19:53 -0700 Subject: [PATCH 02/95] expose RayPickMask to JS, move everything to interface/src/raypick to prevent dependency issues, start working on RayPickManager::update (needs testing) --- interface/src/Application.cpp | 6 +- .../src/raypick}/JointRayPick.cpp | 9 +- .../src/raypick}/JointRayPick.h | 8 +- .../src/raypick}/LaserPointer.cpp | 6 +- .../src/raypick}/LaserPointer.h | 6 +- .../src/raypick}/LaserPointerManager.cpp | 6 +- .../src/raypick}/LaserPointerManager.h | 6 +- .../LaserPointerScriptingInterface.cpp | 19 ++- .../LaserPointerScriptingInterface.h | 4 +- .../src => interface/src/raypick}/RayPick.cpp | 2 +- .../src => interface/src/raypick}/RayPick.h | 2 +- interface/src/raypick/RayPickManager.cpp | 145 ++++++++++++++++++ interface/src/raypick/RayPickManager.h | 97 ++++++++++++ .../src/raypick}/StaticRayPick.cpp | 2 +- .../src/raypick}/StaticRayPick.h | 2 +- libraries/shared/src/RayPickManager.cpp | 54 ------- libraries/shared/src/RayPickManager.h | 50 ------ 17 files changed, 285 insertions(+), 139 deletions(-) rename {libraries/shared/src => interface/src/raypick}/JointRayPick.cpp (64%) rename {libraries/shared/src => interface/src/raypick}/JointRayPick.h (65%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointer.cpp (72%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointer.h (76%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointerManager.cpp (80%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointerManager.h (83%) rename interface/src/{ => raypick}/LaserPointerScriptingInterface.cpp (73%) rename interface/src/{ => raypick}/LaserPointerScriptingInterface.h (95%) rename {libraries/shared/src => interface/src/raypick}/RayPick.cpp (94%) rename {libraries/shared/src => interface/src/raypick}/RayPick.h (97%) create mode 100644 interface/src/raypick/RayPickManager.cpp create mode 100644 interface/src/raypick/RayPickManager.h rename {libraries/shared/src => interface/src/raypick}/StaticRayPick.cpp (95%) rename {libraries/shared/src => interface/src/raypick}/StaticRayPick.h (96%) delete mode 100644 libraries/shared/src/RayPickManager.cpp delete mode 100644 libraries/shared/src/RayPickManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 16e322a142..6fad34b6f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -190,8 +190,8 @@ #include #include #include -#include "LaserPointerScriptingInterface.h" -#include +#include +#include // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -5821,6 +5821,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); + scriptEngine->registerGlobalObject("RayPick", &RayPickManager::getInstance()); + qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); // connect this script engines printedMessage signal to the global ScriptEngines these various messages diff --git a/libraries/shared/src/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp similarity index 64% rename from libraries/shared/src/JointRayPick.cpp rename to interface/src/raypick/JointRayPick.cpp index 4a645fa3fd..8ea48f842f 100644 --- a/libraries/shared/src/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -1,6 +1,6 @@ // // JointRayPick.cpp -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -10,17 +10,18 @@ // #include "JointRayPick.h" -JointRayPick::JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) : +JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), - _offsetTransform(offsetTransform) + _posOffset(posOffset), + _dirOffset(dirOffset) { } const PickRay JointRayPick::getPickRay() { // TODO: // get pose for _jointName - // apply _offsetTransform + // apply offset // create and return PickRay return PickRay(); } diff --git a/libraries/shared/src/JointRayPick.h b/interface/src/raypick/JointRayPick.h similarity index 65% rename from libraries/shared/src/JointRayPick.h rename to interface/src/raypick/JointRayPick.h index cd5de79c69..4b2f7d1071 100644 --- a/libraries/shared/src/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -1,6 +1,6 @@ // // JointRayPick.h -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -14,18 +14,18 @@ #include "RayPick.h" #include -#include "Transform.h" class JointRayPick : public RayPick { public: - JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); const PickRay getPickRay() override; private: QString _jointName; - Transform _offsetTransform; + glm::vec3 _posOffset; + glm::vec3 _dirOffset; }; diff --git a/libraries/controllers/src/controllers/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp similarity index 72% rename from libraries/controllers/src/controllers/LaserPointer.cpp rename to interface/src/raypick/LaserPointer.cpp index 4f3adce875..898df04345 100644 --- a/libraries/controllers/src/controllers/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -1,6 +1,6 @@ // // LaserPointer.cpp -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -13,9 +13,9 @@ #include "RayPickManager.h" #include "JointRayPick.h" -LaserPointer::LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) +LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) { - _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled)); + _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); } LaserPointer::~LaserPointer() { diff --git a/libraries/controllers/src/controllers/LaserPointer.h b/interface/src/raypick/LaserPointer.h similarity index 76% rename from libraries/controllers/src/controllers/LaserPointer.h rename to interface/src/raypick/LaserPointer.h index d09defe7b2..93dd33f305 100644 --- a/libraries/controllers/src/controllers/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -1,6 +1,6 @@ // // LaserPointer.h -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -12,12 +12,12 @@ #define hifi_LaserPointer_h #include -#include "Transform.h" +#include "glm/glm.hpp" class LaserPointer { public: - LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } diff --git a/libraries/controllers/src/controllers/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp similarity index 80% rename from libraries/controllers/src/controllers/LaserPointerManager.cpp rename to interface/src/raypick/LaserPointerManager.cpp index adea77f530..1be2087ffb 100644 --- a/libraries/controllers/src/controllers/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -1,6 +1,6 @@ // // LaserPointerManager.cpp -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -16,8 +16,8 @@ LaserPointerManager& LaserPointerManager::getInstance() { return instance; } -unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled) { - std::shared_ptr laserPointer = std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled); +unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; diff --git a/libraries/controllers/src/controllers/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h similarity index 83% rename from libraries/controllers/src/controllers/LaserPointerManager.h rename to interface/src/raypick/LaserPointerManager.h index 28d354cf98..503db5e459 100644 --- a/libraries/controllers/src/controllers/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -1,6 +1,6 @@ // // LaserPointerManager.h -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -14,7 +14,7 @@ #include #include #include -#include "Transform.h" +#include class LaserPointer; @@ -23,7 +23,7 @@ class LaserPointerManager { public: static LaserPointerManager& getInstance(); - unsigned int createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); diff --git a/interface/src/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp similarity index 73% rename from interface/src/LaserPointerScriptingInterface.cpp rename to interface/src/raypick/LaserPointerScriptingInterface.cpp index a5770a9252..f8bba2bf04 100644 --- a/interface/src/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -1,6 +1,6 @@ // // LaserPointerScriptingInterface.cpp -// interface/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -12,7 +12,8 @@ #include "LaserPointerScriptingInterface.h" #include -#include "Transform.h" +#include "RegisteredMetaTypes.h" +#include "GLMHelpers.h" LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { static LaserPointerScriptingInterface instance; @@ -25,10 +26,14 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop if (propertyMap["joint"].isValid()) { QString jointName = propertyMap["joint"].toString(); - Transform offsetTransform; - if (propertyMap["offsetTransform"].isValid()) { - // TODO: - // convert transform + glm::vec3 posOffset = Vectors::ZERO; + if (propertyMap["posOffset"].isValid()) { + posOffset = vec3FromVariant(propertyMap["posOffset"]); + } + + glm::vec3 dirOffset = Vectors::FRONT; + if (propertyMap["dirOffset"].isValid()) { + posOffset = vec3FromVariant(propertyMap["dirOffset"]); } uint16_t filter = 0; @@ -49,7 +54,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop // TODO: // handle render state properties - return LaserPointerManager::getInstance().createLaserPointer(jointName, offsetTransform, filter, maxDistance, enabled); + return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, enabled); } else { return 0; } diff --git a/interface/src/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h similarity index 95% rename from interface/src/LaserPointerScriptingInterface.h rename to interface/src/raypick/LaserPointerScriptingInterface.h index c455843d03..428d722bbb 100644 --- a/interface/src/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -1,6 +1,6 @@ // // LaserPointerScriptingInterface.h -// interface/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -13,7 +13,7 @@ #include -#include "controllers\LaserPointerManager.h" +#include "LaserPointerManager.h" class LaserPointerScriptingInterface : public QObject { Q_OBJECT diff --git a/libraries/shared/src/RayPick.cpp b/interface/src/raypick/RayPick.cpp similarity index 94% rename from libraries/shared/src/RayPick.cpp rename to interface/src/raypick/RayPick.cpp index 674913e2e0..e807ef23ff 100644 --- a/libraries/shared/src/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -1,6 +1,6 @@ // // RayPick.cpp -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/shared/src/RayPick.h b/interface/src/raypick/RayPick.h similarity index 97% rename from libraries/shared/src/RayPick.h rename to interface/src/raypick/RayPick.h index 8a292bf5f7..7ad2d9f83f 100644 --- a/libraries/shared/src/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -1,6 +1,6 @@ // // RayPick.h -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp new file mode 100644 index 0000000000..bb25c8f168 --- /dev/null +++ b/interface/src/raypick/RayPickManager.cpp @@ -0,0 +1,145 @@ +// +// RayPickManager.cpp +// interface/src/raypick +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPickManager.h" +#include "RayPick.h" + +#include "Application.h" +#include "EntityScriptingInterface.h" +#include "ui/overlays/Overlays.h" +#include "avatar/AvatarManager.h" +#include "DependencyManager.h" + +RayPickManager& RayPickManager::getInstance() { + static RayPickManager instance; + return instance; +} + +// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer +bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask) { + if (cache.contains(ray) && cache[ray].contains(mask)) { + if (cache[ray][mask].getDistance() < res.getDistance() && cache[ray][mask].getDistance() < rayPick->getMaxDistance()) { + res = cache[ray][mask]; + } + return true; + } + return false; +} + +void RayPickManager::update() { + QHash, QHash> results; + for (auto &rayPick : _rayPicks) { + if (!rayPick->isEnabled() || rayPick->getFilter() == RayPickMask::PICK_NOTHING || rayPick->getMaxDistance() < 0.0f) { + continue; + } + + PickRay ray = rayPick->getPickRay(); + // TODO: + // get rid of this and make PickRay hashable + QPair rayKey = QPair(ray.origin, ray.direction); + RayPickResult res; // start with FLT_MAX distance + + if (rayPick->getFilter() & RayPickMask::PICK_ENTITIES) { + RayToEntityIntersectionResult entityRes; + if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + } + } + else { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + } + } + if (entityRes.intersects) { + res = RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal); + // add to cache + } + } + + if (rayPick->getFilter() & RayPickMask::PICK_OVERLAYS) { + RayToOverlayIntersectionResult overlayRes; + if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + } + } + else { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + } + } + if (overlayRes.intersects) { + res = RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal); + // add to cache + } + } + + if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_AVATARS)) { + RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, QScriptValue(), QScriptValue()); + if (avatarRes.intersects) { + res = RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection); + // add to cache + } + } + } + + } +} + +unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { + // TODO: + // use lock and defer adding to prevent issues + _rayPicks[_nextUID] = rayPick; + return _nextUID++; +} + +void RayPickManager::removeRayPick(const unsigned int uid) { + // TODO: + // use lock and defer removing to prevent issues + _rayPicks.remove(uid); +} + +void RayPickManager::enableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer enabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->enable(); + } +} + +void RayPickManager::disableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer disabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->disable(); + } +} diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h new file mode 100644 index 0000000000..ac700118f6 --- /dev/null +++ b/interface/src/raypick/RayPickManager.h @@ -0,0 +1,97 @@ +// +// RayPickManager.h +// interface/src/raypick +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPickManager_h +#define hifi_RayPickManager_h + +#include "RegisteredMetaTypes.h" + +#include +#include +#include + +class RayPick; + +enum RayPickMask { + PICK_NOTHING = 0, + PICK_ENTITIES = 1, + PICK_OVERLAYS = 2, + PICK_AVATARS = 4, + PICK_HUD = 8, + + PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) + + PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements + PICK_INCLUDE_NONCOLLIDABLE = 64, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements + + PICK_ALL_INTERSECTIONS = 128 // if not set, returns closest intersection, otherwise, returns list of all intersections +}; + +// TODO: +// move/improve this and register it as a meta type +class RayPickResult { + +public: + RayPickResult() {} + RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + _objectID(objectID), _distance(distance), _intersection(intersection), _surfaceNormal(surfaceNormal) {} + + const QUuid& getUID() { return _objectID; } + const float getDistance() { return _distance; } + const glm::vec3& getIntersection() { return _intersection; } + const glm::vec3& getSurfaceNormal() { return _surfaceNormal; } + +private: + //Type type; + QUuid _objectID { 0 }; + float _distance { FLT_MAX }; + glm::vec3 _intersection { NAN }; + glm::vec3 _surfaceNormal { NAN }; +}; + +class RayPickManager : public QObject { + Q_OBJECT + Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) + Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) + Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) + Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) + Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) + Q_PROPERTY(unsigned int PICK_BOUNDING_BOX READ PICK_BOUNDING_BOX CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) + Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) + +public: + static RayPickManager& getInstance(); + + void update(); + bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask); + unsigned int addRayPick(std::shared_ptr rayPick); + void removeRayPick(const unsigned int uid); + void enableRayPick(const unsigned int uid); + void disableRayPick(const unsigned int uid); + +private: + QHash> _rayPicks; + unsigned int _nextUID { 1 }; // 0 is invalid + + const unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } + const unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } + const unsigned int PICK_OVERLAYS() { return RayPickMask::PICK_OVERLAYS; } + const unsigned int PICK_AVATARS() { return RayPickMask::PICK_AVATARS; } + const unsigned int PICK_HUD() { return RayPickMask::PICK_HUD; } + const unsigned int PICK_BOUNDING_BOX() { return RayPickMask::PICK_BOUNDING_BOX; } + const unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickMask::PICK_INCLUDE_INVISIBLE; } + const unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; } + const unsigned int PICK_ALL_INTERSECTIONS() { return RayPickMask::PICK_ALL_INTERSECTIONS; } + +}; + +#endif hifi_RayPickManager_h \ No newline at end of file diff --git a/libraries/shared/src/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp similarity index 95% rename from libraries/shared/src/StaticRayPick.cpp rename to interface/src/raypick/StaticRayPick.cpp index 2ebe431b00..b3bce16b58 100644 --- a/libraries/shared/src/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -1,6 +1,6 @@ // // StaticRayPick.cpp -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/shared/src/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h similarity index 96% rename from libraries/shared/src/StaticRayPick.h rename to interface/src/raypick/StaticRayPick.h index 6424b731c7..6d3df21859 100644 --- a/libraries/shared/src/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -1,6 +1,6 @@ // // StaticRayPick.h -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/shared/src/RayPickManager.cpp b/libraries/shared/src/RayPickManager.cpp deleted file mode 100644 index 5c5ebd8c10..0000000000 --- a/libraries/shared/src/RayPickManager.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// RayPickManager.cpp -// libraries/shared/src -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "RayPickManager.h" -#include "RayPick.h" - -RayPickManager& RayPickManager::getInstance() { - static RayPickManager instance; - return instance; -} - -void RayPickManager::update() { - /*** - - somehow calculate minimum number of intersection tests, update raypicks accordingly - -one option : - loop over all raypicks{ loop over all necessary intersection tests and take min distance less than rayPick->maxDistance, but keep cache of this frame's previous tests to prevent duplicate intersection tests } - ***/ -} - -unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { - // TODO: - // use lock and defer adding to prevent issues - _rayPicks[_nextUID] = rayPick; - return _nextUID++; -} - -void RayPickManager::removeRayPick(const unsigned int uid) { - // TODO: - // use lock and defer removing to prevent issues - _rayPicks.remove(uid); -} - -void RayPickManager::enableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer enabling to prevent issues - if (_rayPicks.contains(uid)) { - _rayPicks[uid]->enable(); - } -} - -void RayPickManager::disableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer disabling to prevent issues - if (_rayPicks.contains(uid)) { - _rayPicks[uid]->disable(); - } -} diff --git a/libraries/shared/src/RayPickManager.h b/libraries/shared/src/RayPickManager.h deleted file mode 100644 index c296c14af7..0000000000 --- a/libraries/shared/src/RayPickManager.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// RayPickManager.h -// libraries/shared/src -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#ifndef hifi_RayPickManager_h -#define hifi_RayPickManager_h - -#include -#include - -class RayPick; - -enum RayPickMask { - PICK_NOTHING = 0, - PICK_ENTITIES = 1, - PICK_AVATARS = 2, - PICK_OVERLAYS = 4, - PICK_HUD = 8, - - PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) - - PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements - - PICK_ALL_INTERSECTIONS = 64 // if not set, returns closest intersection, otherwise, returns list of all intersections -}; - -class RayPickManager { - -public: - static RayPickManager& getInstance(); - - void update(); - unsigned int addRayPick(std::shared_ptr rayPick); - void removeRayPick(const unsigned int uid); - void enableRayPick(const unsigned int uid); - void disableRayPick(const unsigned int uid); - -private: - QHash> _rayPicks; - unsigned int _nextUID { 1 }; // 0 is invalid - -}; - -#endif hifi_RayPickManager_h \ No newline at end of file From 3ac369d782c3936891012a142df3e8b9f1543489 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 11 Jul 2017 17:07:53 -0700 Subject: [PATCH 03/95] framework for LaserPointers and abstracted RayPicking on C++ side, including JS API --- interface/src/Application.cpp | 8 +++ .../src/LaserPointerScriptingInterface.cpp | 56 +++++++++++++++++++ .../src/LaserPointerScriptingInterface.h | 33 +++++++++++ .../src/controllers/LaserPointer.cpp | 35 ++++++++++++ .../src/controllers/LaserPointer.h | 34 +++++++++++ .../src/controllers/LaserPointerManager.cpp | 36 ++++++++++++ .../src/controllers/LaserPointerManager.h | 36 ++++++++++++ libraries/shared/src/JointRayPick.cpp | 26 +++++++++ libraries/shared/src/JointRayPick.h | 32 +++++++++++ libraries/shared/src/RayPick.cpp | 18 ++++++ libraries/shared/src/RayPick.h | 42 ++++++++++++++ libraries/shared/src/RayPickManager.cpp | 54 ++++++++++++++++++ libraries/shared/src/RayPickManager.h | 50 +++++++++++++++++ libraries/shared/src/StaticRayPick.cpp | 17 ++++++ libraries/shared/src/StaticRayPick.h | 28 ++++++++++ 15 files changed, 505 insertions(+) create mode 100644 interface/src/LaserPointerScriptingInterface.cpp create mode 100644 interface/src/LaserPointerScriptingInterface.h create mode 100644 libraries/controllers/src/controllers/LaserPointer.cpp create mode 100644 libraries/controllers/src/controllers/LaserPointer.h create mode 100644 libraries/controllers/src/controllers/LaserPointerManager.cpp create mode 100644 libraries/controllers/src/controllers/LaserPointerManager.h create mode 100644 libraries/shared/src/JointRayPick.cpp create mode 100644 libraries/shared/src/JointRayPick.h create mode 100644 libraries/shared/src/RayPick.cpp create mode 100644 libraries/shared/src/RayPick.h create mode 100644 libraries/shared/src/RayPickManager.cpp create mode 100644 libraries/shared/src/RayPickManager.h create mode 100644 libraries/shared/src/StaticRayPick.cpp create mode 100644 libraries/shared/src/StaticRayPick.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ddd1870723..16e322a142 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -190,6 +190,8 @@ #include #include #include +#include "LaserPointerScriptingInterface.h" +#include // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -4916,6 +4918,11 @@ void Application::update(float deltaTime) { _overlays.update(deltaTime); } + { + PROFILE_RANGE(app, "RayPick"); + RayPickManager::getInstance().update(); + } + // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the // loadViewFrumstum() method will get the correct details from the camera @@ -5761,6 +5768,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AvatarBookmarks", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LocationBookmarks", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("LaserPointers", LaserPointerScriptingInterface::getInstance()); // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); diff --git a/interface/src/LaserPointerScriptingInterface.cpp b/interface/src/LaserPointerScriptingInterface.cpp new file mode 100644 index 0000000000..a5770a9252 --- /dev/null +++ b/interface/src/LaserPointerScriptingInterface.cpp @@ -0,0 +1,56 @@ +// +// LaserPointerScriptingInterface.cpp +// interface/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "LaserPointerScriptingInterface.h" + +#include +#include "Transform.h" + +LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { + static LaserPointerScriptingInterface instance; + return &instance; +} + +uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { + QVariantMap propertyMap = properties.toMap(); + + if (propertyMap["joint"].isValid()) { + QString jointName = propertyMap["joint"].toString(); + + Transform offsetTransform; + if (propertyMap["offsetTransform"].isValid()) { + // TODO: + // convert transform + } + + uint16_t filter = 0; + if (propertyMap["filter"].isValid()) { + filter = propertyMap["filter"].toUInt(); + } + + float maxDistance = 0.0f; + if (propertyMap["maxDistance"].isValid()) { + maxDistance = propertyMap["maxDistance"].toFloat(); + } + + bool enabled = false; + if (propertyMap["enabled"].isValid()) { + enabled = propertyMap["enabled"].toBool(); + } + + // TODO: + // handle render state properties + + return LaserPointerManager::getInstance().createLaserPointer(jointName, offsetTransform, filter, maxDistance, enabled); + } else { + return 0; + } +} \ No newline at end of file diff --git a/interface/src/LaserPointerScriptingInterface.h b/interface/src/LaserPointerScriptingInterface.h new file mode 100644 index 0000000000..c455843d03 --- /dev/null +++ b/interface/src/LaserPointerScriptingInterface.h @@ -0,0 +1,33 @@ +// +// LaserPointerScriptingInterface.h +// interface/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_LaserPointerScriptingInterface_h +#define hifi_LaserPointerScriptingInterface_h + +#include + +#include "controllers\LaserPointerManager.h" + +class LaserPointerScriptingInterface : public QObject { + Q_OBJECT + +public: + static LaserPointerScriptingInterface* getInstance(); + +public slots: + Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties); + Q_INVOKABLE void enableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().enableLaserPointer(uid); } + Q_INVOKABLE void disableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().disableLaserPointer(uid); } + Q_INVOKABLE void removeLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().removeLaserPointer(uid); } + //Q_INVOKABLE IntersectionResults getLaserPointerCollisionResults(unsigned int uid) { LaserPointerManager::getInstance().getLaserPointerCollisionResults(uid); } + +}; + +#endif hifi_LaserPointerScriptingInterface_h \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointer.cpp b/libraries/controllers/src/controllers/LaserPointer.cpp new file mode 100644 index 0000000000..4f3adce875 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointer.cpp @@ -0,0 +1,35 @@ +// +// LaserPointer.cpp +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "LaserPointer.h" + +#include "RayPickManager.h" +#include "JointRayPick.h" + +LaserPointer::LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) +{ + _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled)); +} + +LaserPointer::~LaserPointer() { + RayPickManager::getInstance().removeRayPick(_rayPickUID); +} + +void LaserPointer::enable() { + RayPickManager::getInstance().enableRayPick(_rayPickUID); + // TODO: + // turn on rendering +} + +void LaserPointer::disable() { + RayPickManager::getInstance().disableRayPick(_rayPickUID); + // TODO: + // turn off rendering +} \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointer.h b/libraries/controllers/src/controllers/LaserPointer.h new file mode 100644 index 0000000000..d09defe7b2 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointer.h @@ -0,0 +1,34 @@ +// +// LaserPointer.h +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_LaserPointer_h +#define hifi_LaserPointer_h + +#include +#include "Transform.h" + +class LaserPointer { + +public: + LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + ~LaserPointer(); + + unsigned int getUID() { return _rayPickUID; } + void enable(); + void disable(); + + // void setRenderState(const QString& stateName); + // void setRenderStateProperties(const QHash& renderStateProperties); + +private: + unsigned int _rayPickUID; +}; + +#endif hifi_LaserPointer_h \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointerManager.cpp b/libraries/controllers/src/controllers/LaserPointerManager.cpp new file mode 100644 index 0000000000..adea77f530 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointerManager.cpp @@ -0,0 +1,36 @@ +// +// LaserPointerManager.cpp +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "LaserPointerManager.h" +#include "LaserPointer.h" + +LaserPointerManager& LaserPointerManager::getInstance() { + static LaserPointerManager instance; + return instance; +} + +unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled); + unsigned int uid = laserPointer->getUID(); + _laserPointers[uid] = laserPointer; + return uid; +} + +void LaserPointerManager::enableLaserPointer(const unsigned int uid) { + if (_laserPointers.contains(uid)) { + _laserPointers[uid]->enable(); + } +} + +void LaserPointerManager::disableLaserPointer(const unsigned int uid) { + if (_laserPointers.contains(uid)) { + _laserPointers[uid]->disable(); + } +} \ No newline at end of file diff --git a/libraries/controllers/src/controllers/LaserPointerManager.h b/libraries/controllers/src/controllers/LaserPointerManager.h new file mode 100644 index 0000000000..28d354cf98 --- /dev/null +++ b/libraries/controllers/src/controllers/LaserPointerManager.h @@ -0,0 +1,36 @@ +// +// LaserPointerManager.h +// libraries/controllers/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_LaserPointerManager_h +#define hifi_LaserPointerManager_h + +#include +#include +#include +#include "Transform.h" + +class LaserPointer; + +class LaserPointerManager { + +public: + static LaserPointerManager& getInstance(); + + unsigned int createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } + void enableLaserPointer(const unsigned int uid); + void disableLaserPointer(const unsigned int uid); + +private: + QHash> _laserPointers; + +}; + +#endif hifi_LaserPointerManager_h \ No newline at end of file diff --git a/libraries/shared/src/JointRayPick.cpp b/libraries/shared/src/JointRayPick.cpp new file mode 100644 index 0000000000..4a645fa3fd --- /dev/null +++ b/libraries/shared/src/JointRayPick.cpp @@ -0,0 +1,26 @@ +// +// JointRayPick.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "JointRayPick.h" + +JointRayPick::JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) : + RayPick(filter, maxDistance, enabled), + _jointName(jointName), + _offsetTransform(offsetTransform) +{ +} + +const PickRay JointRayPick::getPickRay() { + // TODO: + // get pose for _jointName + // apply _offsetTransform + // create and return PickRay + return PickRay(); +} diff --git a/libraries/shared/src/JointRayPick.h b/libraries/shared/src/JointRayPick.h new file mode 100644 index 0000000000..cd5de79c69 --- /dev/null +++ b/libraries/shared/src/JointRayPick.h @@ -0,0 +1,32 @@ +// +// JointRayPick.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_JointRayPick_h +#define hifi_JointRayPick_h + +#include "RayPick.h" + +#include +#include "Transform.h" + +class JointRayPick : public RayPick { + +public: + JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + + const PickRay getPickRay() override; + +private: + QString _jointName; + Transform _offsetTransform; + +}; + +#endif hifi_JointRayPick_h \ No newline at end of file diff --git a/libraries/shared/src/RayPick.cpp b/libraries/shared/src/RayPick.cpp new file mode 100644 index 0000000000..674913e2e0 --- /dev/null +++ b/libraries/shared/src/RayPick.cpp @@ -0,0 +1,18 @@ +// +// RayPick.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPick.h" + +RayPick::RayPick(const uint16_t filter, const float maxDistance, const bool enabled) : + _filter(filter), + _maxDistance(maxDistance), + _enabled(enabled) +{ +} diff --git a/libraries/shared/src/RayPick.h b/libraries/shared/src/RayPick.h new file mode 100644 index 0000000000..8a292bf5f7 --- /dev/null +++ b/libraries/shared/src/RayPick.h @@ -0,0 +1,42 @@ +// +// RayPick.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPick_h +#define hifi_RayPick_h + +#include +#include "RegisteredMetaTypes.h" + +class RayPick { + +public: + RayPick(const uint16_t filter, const float maxDistance, const bool enabled); + + virtual const PickRay getPickRay() = 0; + + void enable() { _enabled = true; } + void disable() { _enabled = false; } + + const uint16_t getFilter() { return _filter; } + const float getMaxDistance() { return _maxDistance; } + const bool isEnabled() { return _enabled; } + //const IntersectionResult& getLastIntersectionResult() { return _prevIntersectionResult; } + + //void setIntersectionResult(const IntersectionResult& intersectionResult) { _prevIntersectionResult = intersectionResult; } + +private: + uint16_t _filter; + float _maxDistance; + bool _enabled; + //IntersectionResult _prevIntersectionResult; // set to invalid on disable()? + +}; + +#endif hifi_RayPick_h \ No newline at end of file diff --git a/libraries/shared/src/RayPickManager.cpp b/libraries/shared/src/RayPickManager.cpp new file mode 100644 index 0000000000..5c5ebd8c10 --- /dev/null +++ b/libraries/shared/src/RayPickManager.cpp @@ -0,0 +1,54 @@ +// +// RayPickManager.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPickManager.h" +#include "RayPick.h" + +RayPickManager& RayPickManager::getInstance() { + static RayPickManager instance; + return instance; +} + +void RayPickManager::update() { + /*** + - somehow calculate minimum number of intersection tests, update raypicks accordingly + -one option : + loop over all raypicks{ loop over all necessary intersection tests and take min distance less than rayPick->maxDistance, but keep cache of this frame's previous tests to prevent duplicate intersection tests } + ***/ +} + +unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { + // TODO: + // use lock and defer adding to prevent issues + _rayPicks[_nextUID] = rayPick; + return _nextUID++; +} + +void RayPickManager::removeRayPick(const unsigned int uid) { + // TODO: + // use lock and defer removing to prevent issues + _rayPicks.remove(uid); +} + +void RayPickManager::enableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer enabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->enable(); + } +} + +void RayPickManager::disableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer disabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->disable(); + } +} diff --git a/libraries/shared/src/RayPickManager.h b/libraries/shared/src/RayPickManager.h new file mode 100644 index 0000000000..c296c14af7 --- /dev/null +++ b/libraries/shared/src/RayPickManager.h @@ -0,0 +1,50 @@ +// +// RayPickManager.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPickManager_h +#define hifi_RayPickManager_h + +#include +#include + +class RayPick; + +enum RayPickMask { + PICK_NOTHING = 0, + PICK_ENTITIES = 1, + PICK_AVATARS = 2, + PICK_OVERLAYS = 4, + PICK_HUD = 8, + + PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) + + PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements + + PICK_ALL_INTERSECTIONS = 64 // if not set, returns closest intersection, otherwise, returns list of all intersections +}; + +class RayPickManager { + +public: + static RayPickManager& getInstance(); + + void update(); + unsigned int addRayPick(std::shared_ptr rayPick); + void removeRayPick(const unsigned int uid); + void enableRayPick(const unsigned int uid); + void disableRayPick(const unsigned int uid); + +private: + QHash> _rayPicks; + unsigned int _nextUID { 1 }; // 0 is invalid + +}; + +#endif hifi_RayPickManager_h \ No newline at end of file diff --git a/libraries/shared/src/StaticRayPick.cpp b/libraries/shared/src/StaticRayPick.cpp new file mode 100644 index 0000000000..2ebe431b00 --- /dev/null +++ b/libraries/shared/src/StaticRayPick.cpp @@ -0,0 +1,17 @@ +// +// StaticRayPick.cpp +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "StaticRayPick.h" + +StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const bool enabled) : + RayPick(filter, maxDistance, enabled), + _pickRay(position, direction) +{ +} diff --git a/libraries/shared/src/StaticRayPick.h b/libraries/shared/src/StaticRayPick.h new file mode 100644 index 0000000000..6424b731c7 --- /dev/null +++ b/libraries/shared/src/StaticRayPick.h @@ -0,0 +1,28 @@ +// +// StaticRayPick.h +// libraries/shared/src +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_StaticRayPick_h +#define hifi_StaticRayPick_h + +#include "RayPick.h" + +class StaticRayPick : public RayPick { + +public: + StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + + const PickRay getPickRay() override { return _pickRay; }; + +private: + PickRay _pickRay; + +}; + +#endif hifi_StaticRayPick_h \ No newline at end of file From ea65a04f28c7eebd34624cfcd64c7eff478119b1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 12 Jul 2017 14:19:53 -0700 Subject: [PATCH 04/95] expose RayPickMask to JS, move everything to interface/src/raypick to prevent dependency issues, start working on RayPickManager::update (needs testing) --- interface/src/Application.cpp | 6 +- .../src/raypick}/JointRayPick.cpp | 9 +- .../src/raypick}/JointRayPick.h | 8 +- .../src/raypick}/LaserPointer.cpp | 6 +- .../src/raypick}/LaserPointer.h | 6 +- .../src/raypick}/LaserPointerManager.cpp | 6 +- .../src/raypick}/LaserPointerManager.h | 6 +- .../LaserPointerScriptingInterface.cpp | 19 ++- .../LaserPointerScriptingInterface.h | 4 +- .../src => interface/src/raypick}/RayPick.cpp | 2 +- .../src => interface/src/raypick}/RayPick.h | 2 +- interface/src/raypick/RayPickManager.cpp | 145 ++++++++++++++++++ interface/src/raypick/RayPickManager.h | 97 ++++++++++++ .../src/raypick}/StaticRayPick.cpp | 2 +- .../src/raypick}/StaticRayPick.h | 2 +- libraries/shared/src/RayPickManager.cpp | 54 ------- libraries/shared/src/RayPickManager.h | 50 ------ 17 files changed, 285 insertions(+), 139 deletions(-) rename {libraries/shared/src => interface/src/raypick}/JointRayPick.cpp (64%) rename {libraries/shared/src => interface/src/raypick}/JointRayPick.h (65%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointer.cpp (72%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointer.h (76%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointerManager.cpp (80%) rename {libraries/controllers/src/controllers => interface/src/raypick}/LaserPointerManager.h (83%) rename interface/src/{ => raypick}/LaserPointerScriptingInterface.cpp (73%) rename interface/src/{ => raypick}/LaserPointerScriptingInterface.h (95%) rename {libraries/shared/src => interface/src/raypick}/RayPick.cpp (94%) rename {libraries/shared/src => interface/src/raypick}/RayPick.h (97%) create mode 100644 interface/src/raypick/RayPickManager.cpp create mode 100644 interface/src/raypick/RayPickManager.h rename {libraries/shared/src => interface/src/raypick}/StaticRayPick.cpp (95%) rename {libraries/shared/src => interface/src/raypick}/StaticRayPick.h (96%) delete mode 100644 libraries/shared/src/RayPickManager.cpp delete mode 100644 libraries/shared/src/RayPickManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 16e322a142..6fad34b6f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -190,8 +190,8 @@ #include #include #include -#include "LaserPointerScriptingInterface.h" -#include +#include +#include // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -5821,6 +5821,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); + scriptEngine->registerGlobalObject("RayPick", &RayPickManager::getInstance()); + qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); // connect this script engines printedMessage signal to the global ScriptEngines these various messages diff --git a/libraries/shared/src/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp similarity index 64% rename from libraries/shared/src/JointRayPick.cpp rename to interface/src/raypick/JointRayPick.cpp index 4a645fa3fd..8ea48f842f 100644 --- a/libraries/shared/src/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -1,6 +1,6 @@ // // JointRayPick.cpp -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -10,17 +10,18 @@ // #include "JointRayPick.h" -JointRayPick::JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) : +JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), - _offsetTransform(offsetTransform) + _posOffset(posOffset), + _dirOffset(dirOffset) { } const PickRay JointRayPick::getPickRay() { // TODO: // get pose for _jointName - // apply _offsetTransform + // apply offset // create and return PickRay return PickRay(); } diff --git a/libraries/shared/src/JointRayPick.h b/interface/src/raypick/JointRayPick.h similarity index 65% rename from libraries/shared/src/JointRayPick.h rename to interface/src/raypick/JointRayPick.h index cd5de79c69..4b2f7d1071 100644 --- a/libraries/shared/src/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -1,6 +1,6 @@ // // JointRayPick.h -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -14,18 +14,18 @@ #include "RayPick.h" #include -#include "Transform.h" class JointRayPick : public RayPick { public: - JointRayPick(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); const PickRay getPickRay() override; private: QString _jointName; - Transform _offsetTransform; + glm::vec3 _posOffset; + glm::vec3 _dirOffset; }; diff --git a/libraries/controllers/src/controllers/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp similarity index 72% rename from libraries/controllers/src/controllers/LaserPointer.cpp rename to interface/src/raypick/LaserPointer.cpp index 4f3adce875..898df04345 100644 --- a/libraries/controllers/src/controllers/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -1,6 +1,6 @@ // // LaserPointer.cpp -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -13,9 +13,9 @@ #include "RayPickManager.h" #include "JointRayPick.h" -LaserPointer::LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, const bool enabled) +LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) { - _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled)); + _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); } LaserPointer::~LaserPointer() { diff --git a/libraries/controllers/src/controllers/LaserPointer.h b/interface/src/raypick/LaserPointer.h similarity index 76% rename from libraries/controllers/src/controllers/LaserPointer.h rename to interface/src/raypick/LaserPointer.h index d09defe7b2..93dd33f305 100644 --- a/libraries/controllers/src/controllers/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -1,6 +1,6 @@ // // LaserPointer.h -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -12,12 +12,12 @@ #define hifi_LaserPointer_h #include -#include "Transform.h" +#include "glm/glm.hpp" class LaserPointer { public: - LaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } diff --git a/libraries/controllers/src/controllers/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp similarity index 80% rename from libraries/controllers/src/controllers/LaserPointerManager.cpp rename to interface/src/raypick/LaserPointerManager.cpp index adea77f530..1be2087ffb 100644 --- a/libraries/controllers/src/controllers/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -1,6 +1,6 @@ // // LaserPointerManager.cpp -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -16,8 +16,8 @@ LaserPointerManager& LaserPointerManager::getInstance() { return instance; } -unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled) { - std::shared_ptr laserPointer = std::make_shared(jointName, offsetTransform, filter, maxDistance, enabled); +unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; diff --git a/libraries/controllers/src/controllers/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h similarity index 83% rename from libraries/controllers/src/controllers/LaserPointerManager.h rename to interface/src/raypick/LaserPointerManager.h index 28d354cf98..503db5e459 100644 --- a/libraries/controllers/src/controllers/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -1,6 +1,6 @@ // // LaserPointerManager.h -// libraries/controllers/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -14,7 +14,7 @@ #include #include #include -#include "Transform.h" +#include class LaserPointer; @@ -23,7 +23,7 @@ class LaserPointerManager { public: static LaserPointerManager& getInstance(); - unsigned int createLaserPointer(const QString& jointName, const Transform& offsetTransform, const uint16_t filter, const float maxDistance, bool enabled); + unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); diff --git a/interface/src/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp similarity index 73% rename from interface/src/LaserPointerScriptingInterface.cpp rename to interface/src/raypick/LaserPointerScriptingInterface.cpp index a5770a9252..f8bba2bf04 100644 --- a/interface/src/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -1,6 +1,6 @@ // // LaserPointerScriptingInterface.cpp -// interface/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -12,7 +12,8 @@ #include "LaserPointerScriptingInterface.h" #include -#include "Transform.h" +#include "RegisteredMetaTypes.h" +#include "GLMHelpers.h" LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { static LaserPointerScriptingInterface instance; @@ -25,10 +26,14 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop if (propertyMap["joint"].isValid()) { QString jointName = propertyMap["joint"].toString(); - Transform offsetTransform; - if (propertyMap["offsetTransform"].isValid()) { - // TODO: - // convert transform + glm::vec3 posOffset = Vectors::ZERO; + if (propertyMap["posOffset"].isValid()) { + posOffset = vec3FromVariant(propertyMap["posOffset"]); + } + + glm::vec3 dirOffset = Vectors::FRONT; + if (propertyMap["dirOffset"].isValid()) { + posOffset = vec3FromVariant(propertyMap["dirOffset"]); } uint16_t filter = 0; @@ -49,7 +54,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop // TODO: // handle render state properties - return LaserPointerManager::getInstance().createLaserPointer(jointName, offsetTransform, filter, maxDistance, enabled); + return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, enabled); } else { return 0; } diff --git a/interface/src/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h similarity index 95% rename from interface/src/LaserPointerScriptingInterface.h rename to interface/src/raypick/LaserPointerScriptingInterface.h index c455843d03..428d722bbb 100644 --- a/interface/src/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -1,6 +1,6 @@ // // LaserPointerScriptingInterface.h -// interface/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. @@ -13,7 +13,7 @@ #include -#include "controllers\LaserPointerManager.h" +#include "LaserPointerManager.h" class LaserPointerScriptingInterface : public QObject { Q_OBJECT diff --git a/libraries/shared/src/RayPick.cpp b/interface/src/raypick/RayPick.cpp similarity index 94% rename from libraries/shared/src/RayPick.cpp rename to interface/src/raypick/RayPick.cpp index 674913e2e0..e807ef23ff 100644 --- a/libraries/shared/src/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -1,6 +1,6 @@ // // RayPick.cpp -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/shared/src/RayPick.h b/interface/src/raypick/RayPick.h similarity index 97% rename from libraries/shared/src/RayPick.h rename to interface/src/raypick/RayPick.h index 8a292bf5f7..7ad2d9f83f 100644 --- a/libraries/shared/src/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -1,6 +1,6 @@ // // RayPick.h -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp new file mode 100644 index 0000000000..bb25c8f168 --- /dev/null +++ b/interface/src/raypick/RayPickManager.cpp @@ -0,0 +1,145 @@ +// +// RayPickManager.cpp +// interface/src/raypick +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPickManager.h" +#include "RayPick.h" + +#include "Application.h" +#include "EntityScriptingInterface.h" +#include "ui/overlays/Overlays.h" +#include "avatar/AvatarManager.h" +#include "DependencyManager.h" + +RayPickManager& RayPickManager::getInstance() { + static RayPickManager instance; + return instance; +} + +// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer +bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask) { + if (cache.contains(ray) && cache[ray].contains(mask)) { + if (cache[ray][mask].getDistance() < res.getDistance() && cache[ray][mask].getDistance() < rayPick->getMaxDistance()) { + res = cache[ray][mask]; + } + return true; + } + return false; +} + +void RayPickManager::update() { + QHash, QHash> results; + for (auto &rayPick : _rayPicks) { + if (!rayPick->isEnabled() || rayPick->getFilter() == RayPickMask::PICK_NOTHING || rayPick->getMaxDistance() < 0.0f) { + continue; + } + + PickRay ray = rayPick->getPickRay(); + // TODO: + // get rid of this and make PickRay hashable + QPair rayKey = QPair(ray.origin, ray.direction); + RayPickResult res; // start with FLT_MAX distance + + if (rayPick->getFilter() & RayPickMask::PICK_ENTITIES) { + RayToEntityIntersectionResult entityRes; + if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + } + } + else { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + } + } + if (entityRes.intersects) { + res = RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal); + // add to cache + } + } + + if (rayPick->getFilter() & RayPickMask::PICK_OVERLAYS) { + RayToOverlayIntersectionResult overlayRes; + if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + } + } + else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + } + } + else { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + } + } + if (overlayRes.intersects) { + res = RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal); + // add to cache + } + } + + if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { + if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_AVATARS)) { + RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, QScriptValue(), QScriptValue()); + if (avatarRes.intersects) { + res = RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection); + // add to cache + } + } + } + + } +} + +unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { + // TODO: + // use lock and defer adding to prevent issues + _rayPicks[_nextUID] = rayPick; + return _nextUID++; +} + +void RayPickManager::removeRayPick(const unsigned int uid) { + // TODO: + // use lock and defer removing to prevent issues + _rayPicks.remove(uid); +} + +void RayPickManager::enableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer enabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->enable(); + } +} + +void RayPickManager::disableRayPick(const unsigned int uid) { + // TODO: + // use lock and defer disabling to prevent issues + if (_rayPicks.contains(uid)) { + _rayPicks[uid]->disable(); + } +} diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h new file mode 100644 index 0000000000..ac700118f6 --- /dev/null +++ b/interface/src/raypick/RayPickManager.h @@ -0,0 +1,97 @@ +// +// RayPickManager.h +// interface/src/raypick +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPickManager_h +#define hifi_RayPickManager_h + +#include "RegisteredMetaTypes.h" + +#include +#include +#include + +class RayPick; + +enum RayPickMask { + PICK_NOTHING = 0, + PICK_ENTITIES = 1, + PICK_OVERLAYS = 2, + PICK_AVATARS = 4, + PICK_HUD = 8, + + PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) + + PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements + PICK_INCLUDE_NONCOLLIDABLE = 64, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements + + PICK_ALL_INTERSECTIONS = 128 // if not set, returns closest intersection, otherwise, returns list of all intersections +}; + +// TODO: +// move/improve this and register it as a meta type +class RayPickResult { + +public: + RayPickResult() {} + RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + _objectID(objectID), _distance(distance), _intersection(intersection), _surfaceNormal(surfaceNormal) {} + + const QUuid& getUID() { return _objectID; } + const float getDistance() { return _distance; } + const glm::vec3& getIntersection() { return _intersection; } + const glm::vec3& getSurfaceNormal() { return _surfaceNormal; } + +private: + //Type type; + QUuid _objectID { 0 }; + float _distance { FLT_MAX }; + glm::vec3 _intersection { NAN }; + glm::vec3 _surfaceNormal { NAN }; +}; + +class RayPickManager : public QObject { + Q_OBJECT + Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) + Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) + Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) + Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) + Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) + Q_PROPERTY(unsigned int PICK_BOUNDING_BOX READ PICK_BOUNDING_BOX CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) + Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) + +public: + static RayPickManager& getInstance(); + + void update(); + bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask); + unsigned int addRayPick(std::shared_ptr rayPick); + void removeRayPick(const unsigned int uid); + void enableRayPick(const unsigned int uid); + void disableRayPick(const unsigned int uid); + +private: + QHash> _rayPicks; + unsigned int _nextUID { 1 }; // 0 is invalid + + const unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } + const unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } + const unsigned int PICK_OVERLAYS() { return RayPickMask::PICK_OVERLAYS; } + const unsigned int PICK_AVATARS() { return RayPickMask::PICK_AVATARS; } + const unsigned int PICK_HUD() { return RayPickMask::PICK_HUD; } + const unsigned int PICK_BOUNDING_BOX() { return RayPickMask::PICK_BOUNDING_BOX; } + const unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickMask::PICK_INCLUDE_INVISIBLE; } + const unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; } + const unsigned int PICK_ALL_INTERSECTIONS() { return RayPickMask::PICK_ALL_INTERSECTIONS; } + +}; + +#endif hifi_RayPickManager_h \ No newline at end of file diff --git a/libraries/shared/src/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp similarity index 95% rename from libraries/shared/src/StaticRayPick.cpp rename to interface/src/raypick/StaticRayPick.cpp index 2ebe431b00..b3bce16b58 100644 --- a/libraries/shared/src/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -1,6 +1,6 @@ // // StaticRayPick.cpp -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/shared/src/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h similarity index 96% rename from libraries/shared/src/StaticRayPick.h rename to interface/src/raypick/StaticRayPick.h index 6424b731c7..6d3df21859 100644 --- a/libraries/shared/src/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -1,6 +1,6 @@ // // StaticRayPick.h -// libraries/shared/src +// interface/src/raypick // // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/shared/src/RayPickManager.cpp b/libraries/shared/src/RayPickManager.cpp deleted file mode 100644 index 5c5ebd8c10..0000000000 --- a/libraries/shared/src/RayPickManager.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// RayPickManager.cpp -// libraries/shared/src -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "RayPickManager.h" -#include "RayPick.h" - -RayPickManager& RayPickManager::getInstance() { - static RayPickManager instance; - return instance; -} - -void RayPickManager::update() { - /*** - - somehow calculate minimum number of intersection tests, update raypicks accordingly - -one option : - loop over all raypicks{ loop over all necessary intersection tests and take min distance less than rayPick->maxDistance, but keep cache of this frame's previous tests to prevent duplicate intersection tests } - ***/ -} - -unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { - // TODO: - // use lock and defer adding to prevent issues - _rayPicks[_nextUID] = rayPick; - return _nextUID++; -} - -void RayPickManager::removeRayPick(const unsigned int uid) { - // TODO: - // use lock and defer removing to prevent issues - _rayPicks.remove(uid); -} - -void RayPickManager::enableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer enabling to prevent issues - if (_rayPicks.contains(uid)) { - _rayPicks[uid]->enable(); - } -} - -void RayPickManager::disableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer disabling to prevent issues - if (_rayPicks.contains(uid)) { - _rayPicks[uid]->disable(); - } -} diff --git a/libraries/shared/src/RayPickManager.h b/libraries/shared/src/RayPickManager.h deleted file mode 100644 index c296c14af7..0000000000 --- a/libraries/shared/src/RayPickManager.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// RayPickManager.h -// libraries/shared/src -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#ifndef hifi_RayPickManager_h -#define hifi_RayPickManager_h - -#include -#include - -class RayPick; - -enum RayPickMask { - PICK_NOTHING = 0, - PICK_ENTITIES = 1, - PICK_AVATARS = 2, - PICK_OVERLAYS = 4, - PICK_HUD = 8, - - PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) - - PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements - - PICK_ALL_INTERSECTIONS = 64 // if not set, returns closest intersection, otherwise, returns list of all intersections -}; - -class RayPickManager { - -public: - static RayPickManager& getInstance(); - - void update(); - unsigned int addRayPick(std::shared_ptr rayPick); - void removeRayPick(const unsigned int uid); - void enableRayPick(const unsigned int uid); - void disableRayPick(const unsigned int uid); - -private: - QHash> _rayPicks; - unsigned int _nextUID { 1 }; // 0 is invalid - -}; - -#endif hifi_RayPickManager_h \ No newline at end of file From 916a99c670f7f13666ce1d145b99f8b7acef5168 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 12 Jul 2017 17:12:25 -0700 Subject: [PATCH 05/95] added JS/C++ RayPickResult, working on RayPickManager::update --- interface/src/raypick/LaserPointer.cpp | 4 + interface/src/raypick/LaserPointer.h | 4 + interface/src/raypick/LaserPointerManager.cpp | 10 +- interface/src/raypick/LaserPointerManager.h | 2 + .../raypick/LaserPointerScriptingInterface.h | 3 +- interface/src/raypick/RayPick.h | 6 +- interface/src/raypick/RayPickManager.cpp | 113 ++++++++++++------ interface/src/raypick/RayPickManager.h | 28 +---- libraries/shared/src/RegisteredMetaTypes.cpp | 18 +++ libraries/shared/src/RegisteredMetaTypes.h | 15 +++ 10 files changed, 137 insertions(+), 66 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 898df04345..b190539607 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -32,4 +32,8 @@ void LaserPointer::disable() { RayPickManager::getInstance().disableRayPick(_rayPickUID); // TODO: // turn off rendering +} + +const RayPickResult& LaserPointer::getPrevRayPickResult() { + return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 93dd33f305..a65c6a9748 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -14,6 +14,8 @@ #include #include "glm/glm.hpp" +class RayPickResult; + class LaserPointer { public: @@ -27,6 +29,8 @@ public: // void setRenderState(const QString& stateName); // void setRenderStateProperties(const QHash& renderStateProperties); + const RayPickResult& getPrevRayPickResult(); + private: unsigned int _rayPickUID; }; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 1be2087ffb..2e7b084d73 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -10,6 +10,7 @@ // #include "LaserPointerManager.h" #include "LaserPointer.h" +#include "RayPick.h" LaserPointerManager& LaserPointerManager::getInstance() { static LaserPointerManager instance; @@ -33,4 +34,11 @@ void LaserPointerManager::disableLaserPointer(const unsigned int uid) { if (_laserPointers.contains(uid)) { _laserPointers[uid]->disable(); } -} \ No newline at end of file +} + +const RayPickResult& LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { + if (_laserPointers.contains(uid)) { + return _laserPointers[uid]->getPrevRayPickResult(); + } + return RayPickResult(); +} diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 503db5e459..f8b3ae1a26 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -17,6 +17,7 @@ #include class LaserPointer; +class RayPickResult; class LaserPointerManager { @@ -27,6 +28,7 @@ public: void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); + const RayPickResult& getPrevRayPickResult(const unsigned int uid); private: QHash> _laserPointers; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 428d722bbb..8d6758119a 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -14,6 +14,7 @@ #include #include "LaserPointerManager.h" +#include "RegisteredMetaTypes.h" class LaserPointerScriptingInterface : public QObject { Q_OBJECT @@ -26,7 +27,7 @@ public slots: Q_INVOKABLE void enableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().enableLaserPointer(uid); } Q_INVOKABLE void disableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().disableLaserPointer(uid); } Q_INVOKABLE void removeLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().removeLaserPointer(uid); } - //Q_INVOKABLE IntersectionResults getLaserPointerCollisionResults(unsigned int uid) { LaserPointerManager::getInstance().getLaserPointerCollisionResults(uid); } + Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return LaserPointerManager::getInstance().getPrevRayPickResult(uid); } }; diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 7ad2d9f83f..512512dc2f 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -27,15 +27,15 @@ public: const uint16_t getFilter() { return _filter; } const float getMaxDistance() { return _maxDistance; } const bool isEnabled() { return _enabled; } - //const IntersectionResult& getLastIntersectionResult() { return _prevIntersectionResult; } + const RayPickResult& getPrevRayPickResult() { return _prevResult; } - //void setIntersectionResult(const IntersectionResult& intersectionResult) { _prevIntersectionResult = intersectionResult; } + void setRayPickResult(const RayPickResult& rayPickResult) { _prevResult = rayPickResult; } private: uint16_t _filter; float _maxDistance; bool _enabled; - //IntersectionResult _prevIntersectionResult; // set to invalid on disable()? + RayPickResult _prevResult; }; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index bb25c8f168..5a242c4f3b 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -9,12 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "RayPickManager.h" + #include "RayPick.h" #include "Application.h" #include "EntityScriptingInterface.h" #include "ui/overlays/Overlays.h" #include "avatar/AvatarManager.h" +#include "scripting/HMDScriptingInterface.h" #include "DependencyManager.h" RayPickManager& RayPickManager::getInstance() { @@ -23,9 +25,9 @@ RayPickManager& RayPickManager::getInstance() { } // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer -bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask) { +bool RayPickManager::checkAndCompareCachedResults(QPair& ray, QHash, QHash>& cache, RayPickResult& res, unsigned int mask) { if (cache.contains(ray) && cache[ray].contains(mask)) { - if (cache[ray][mask].getDistance() < res.getDistance() && cache[ray][mask].getDistance() < rayPick->getMaxDistance()) { + if (cache[ray][mask].distance < res.distance) { res = cache[ray][mask]; } return true; @@ -33,6 +35,18 @@ bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPi return false; } +void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, + QPair& ray, QHash, QHash>& cache) { + if (intersects) { + cache[ray][mask] = resTemp; + if (resTemp.distance < res.distance) { + res = resTemp; + } + } else { + cache[ray][mask] = RayPickResult(); + } +} + void RayPickManager::update() { QHash, QHash> results; for (auto &rayPick : _rayPicks) { @@ -44,74 +58,92 @@ void RayPickManager::update() { // TODO: // get rid of this and make PickRay hashable QPair rayKey = QPair(ray.origin, ray.direction); - RayPickResult res; // start with FLT_MAX distance + RayPickResult res; if (rayPick->getFilter() & RayPickMask::PICK_ENTITIES) { RayToEntityIntersectionResult entityRes; + bool fromCache = true; if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + fromCache = false; } - } - else { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES)) { + } else { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + fromCache = false; } } - if (entityRes.intersects) { - res = RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal); - // add to cache + + if (!fromCache) { + unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); + cacheResult(entityRes.intersects, RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal), + RayPickMask::PICK_ENTITIES | mask, res, rayKey, results); } } if (rayPick->getFilter() & RayPickMask::PICK_OVERLAYS) { RayToOverlayIntersectionResult overlayRes; + bool fromCache = true; if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + fromCache = false; } - } - else { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { + } else { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + fromCache = false; } } - if (overlayRes.intersects) { - res = RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal); - // add to cache + + if (!fromCache) { + unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); + cacheResult(overlayRes.intersects, RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal), + RayPickMask::PICK_OVERLAYS | mask, res, rayKey, results); } } if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_AVATARS)) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_AVATARS)) { RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, QScriptValue(), QScriptValue()); - if (avatarRes.intersects) { - res = RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection); - // add to cache - } + cacheResult(avatarRes.intersects, RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), RayPickMask::PICK_AVATARS, res, rayKey, results); } } + // Can't intersect with HUD in desktop mode + if (rayPick->getFilter() & RayPickMask::PICK_HUD && DependencyManager::get()->isHMDMode()) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_HUD)) { + glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(ray.origin, ray.direction); + cacheResult(true, RayPickResult(0, glm::distance(ray.origin, hudRes), hudRes), RayPickMask::PICK_HUD, res, rayKey, results); + } + } + + if (res.distance < rayPick->getMaxDistance()) { + rayPick->setRayPickResult(res); + } else { + rayPick->setRayPickResult(RayPickResult()); + } } } @@ -129,17 +161,22 @@ void RayPickManager::removeRayPick(const unsigned int uid) { } void RayPickManager::enableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer enabling to prevent issues if (_rayPicks.contains(uid)) { _rayPicks[uid]->enable(); } } void RayPickManager::disableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer disabling to prevent issues if (_rayPicks.contains(uid)) { _rayPicks[uid]->disable(); } } + +const RayPickResult& RayPickManager::getPrevRayPickResult(const unsigned int uid) { + // TODO: + // does this need to lock the individual ray? what happens with concurrent set/get? + if (_rayPicks.contains(uid)) { + return _rayPicks[uid]->getPrevRayPickResult(); + } + return RayPickResult(); +} diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index ac700118f6..8a98677776 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -18,6 +18,7 @@ #include class RayPick; +class RayPickResult; enum RayPickMask { PICK_NOTHING = 0, @@ -34,28 +35,6 @@ enum RayPickMask { PICK_ALL_INTERSECTIONS = 128 // if not set, returns closest intersection, otherwise, returns list of all intersections }; -// TODO: -// move/improve this and register it as a meta type -class RayPickResult { - -public: - RayPickResult() {} - RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : - _objectID(objectID), _distance(distance), _intersection(intersection), _surfaceNormal(surfaceNormal) {} - - const QUuid& getUID() { return _objectID; } - const float getDistance() { return _distance; } - const glm::vec3& getIntersection() { return _intersection; } - const glm::vec3& getSurfaceNormal() { return _surfaceNormal; } - -private: - //Type type; - QUuid _objectID { 0 }; - float _distance { FLT_MAX }; - glm::vec3 _intersection { NAN }; - glm::vec3 _surfaceNormal { NAN }; -}; - class RayPickManager : public QObject { Q_OBJECT Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) @@ -72,11 +51,14 @@ public: static RayPickManager& getInstance(); void update(); - bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask); + bool checkAndCompareCachedResults(QPair& ray, QHash, QHash>& cache, RayPickResult& res, unsigned int mask); + void cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, + QPair& ray, QHash, QHash>& cache); unsigned int addRayPick(std::shared_ptr rayPick); void removeRayPick(const unsigned int uid); void enableRayPick(const unsigned int uid); void disableRayPick(const unsigned int uid); + const RayPickResult& getPrevRayPickResult(const unsigned int uid); private: QHash> _rayPicks; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index b30637c83f..1565777666 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -34,6 +34,7 @@ int vec2MetaTypeId = qRegisterMetaType(); int quatMetaTypeId = qRegisterMetaType(); int xColorMetaTypeId = qRegisterMetaType(); int pickRayMetaTypeId = qRegisterMetaType(); +int rayPickResultMetaTypeId = qRegisterMetaType(); int collisionMetaTypeId = qRegisterMetaType(); int qMapURLStringMetaTypeId = qRegisterMetaType>(); int socketErrorMetaTypeId = qRegisterMetaType(); @@ -56,6 +57,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); + qScriptRegisterMetaType(engine, rayPickResultToScriptValue, rayPickResultFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); @@ -751,6 +753,22 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { } } +QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult) { + QScriptValue obj = engine->newObject(); + QScriptValue objectID = quuidToScriptValue(engine, rayPickResult.objectID); + obj.setProperty("objectID", objectID); + obj.setProperty("distance", rayPickResult.distance); + QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection); + obj.setProperty("intersection", intersection); + QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); + return obj; +} + +void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult) { + // TODO: cannot currently accept RayPickResults from JS +} + QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) { QScriptValue obj = engine->newObject(); obj.setProperty("type", collision.type); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 123c769a96..7d9ba941a9 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -136,6 +136,21 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); +class RayPickResult { +public: + RayPickResult() {} + RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) {} + //Type type; + QUuid objectID { 0 }; + float distance { FLT_MAX }; + glm::vec3 intersection { NAN }; + glm::vec3 surfaceNormal { NAN }; +}; +Q_DECLARE_METATYPE(RayPickResult) +QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult); +void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult); + enum ContactEventType { CONTACT_EVENT_TYPE_START, CONTACT_EVENT_TYPE_CONTINUE, From 783750a0bcd32330ab0c79698d4760957f9fc6cb Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 13 Jul 2017 14:47:24 -0700 Subject: [PATCH 06/95] update jointraypicks from joints, dirOffset needs work --- interface/src/raypick/JointRayPick.cpp | 29 +++++++++++++++---- interface/src/raypick/JointRayPick.h | 2 +- .../LaserPointerScriptingInterface.cpp | 3 +- interface/src/raypick/RayPick.h | 4 +-- interface/src/raypick/RayPickManager.cpp | 10 +++++-- interface/src/raypick/StaticRayPick.cpp | 5 ++++ interface/src/raypick/StaticRayPick.h | 2 +- 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index 8ea48f842f..9309f0d826 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -10,6 +10,9 @@ // #include "JointRayPick.h" +#include "DependencyManager.h" +#include "avatar/AvatarManager.h" + JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), @@ -18,10 +21,26 @@ JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, { } -const PickRay JointRayPick::getPickRay() { - // TODO: - // get pose for _jointName - // apply offset - // create and return PickRay +const PickRay JointRayPick::getPickRay(bool& valid) { + auto myAvatar = DependencyManager::get()->getMyAvatar(); + int jointIndex = myAvatar->getJointIndex(_jointName); + if (jointIndex != -1) { + glm::vec3 jointPos = myAvatar->getAbsoluteJointTranslationInObjectFrame(jointIndex); + glm::quat jointRot = myAvatar->getAbsoluteJointRotationInObjectFrame(jointIndex); + glm::vec3 avatarPos = myAvatar->getPosition(); + glm::quat avatarRot = myAvatar->getOrientation(); + + glm::vec3 pos = avatarPos + (avatarRot * jointPos); + glm::quat rot = avatarRot * jointRot; + + // Apply offset + pos = pos + (rot * _posOffset); + glm::vec3 dir = rot * glm::normalize(_dirOffset); + + valid = true; + return PickRay(pos, dir); + } + + valid = false; return PickRay(); } diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index 4b2f7d1071..54d393ab46 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -20,7 +20,7 @@ class JointRayPick : public RayPick { public: JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay() override; + const PickRay getPickRay(bool& valid) override; private: QString _jointName; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index f8bba2bf04..ef87b1780c 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -26,12 +26,13 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop if (propertyMap["joint"].isValid()) { QString jointName = propertyMap["joint"].toString(); + // x = upward, y = forward, z = lateral glm::vec3 posOffset = Vectors::ZERO; if (propertyMap["posOffset"].isValid()) { posOffset = vec3FromVariant(propertyMap["posOffset"]); } - glm::vec3 dirOffset = Vectors::FRONT; + glm::vec3 dirOffset = Vectors::UP; if (propertyMap["dirOffset"].isValid()) { posOffset = vec3FromVariant(propertyMap["dirOffset"]); } diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 512512dc2f..855cd53ba8 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -17,9 +17,9 @@ class RayPick { public: - RayPick(const uint16_t filter, const float maxDistance, const bool enabled); + RayPick(const uint16_t filter, const float maxDistance, const bool enabled); - virtual const PickRay getPickRay() = 0; + virtual const PickRay getPickRay(bool& valid) = 0; void enable() { _enabled = true; } void disable() { _enabled = false; } diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 5a242c4f3b..d56d9cb501 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -54,7 +54,13 @@ void RayPickManager::update() { continue; } - PickRay ray = rayPick->getPickRay(); + bool valid; + PickRay ray = rayPick->getPickRay(valid); + + if (!valid) { + continue; + } + // TODO: // get rid of this and make PickRay hashable QPair rayKey = QPair(ray.origin, ray.direction); @@ -139,7 +145,7 @@ void RayPickManager::update() { } } - if (res.distance < rayPick->getMaxDistance()) { + if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { rayPick->setRayPickResult(res); } else { rayPick->setRayPickResult(RayPickResult()); diff --git a/interface/src/raypick/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp index b3bce16b58..9edd992a17 100644 --- a/interface/src/raypick/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -15,3 +15,8 @@ StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& directi _pickRay(position, direction) { } + +const PickRay StaticRayPick::getPickRay(bool& valid) { + valid = true; + return _pickRay; +} \ No newline at end of file diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index 6d3df21859..f4f2b769e3 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -18,7 +18,7 @@ class StaticRayPick : public RayPick { public: StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay() override { return _pickRay; }; + const PickRay getPickRay(bool& valid) override; private: PickRay _pickRay; From 3a35cd128fd0bb36621fb2d541f4300443611929 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 13 Jul 2017 16:09:21 -0700 Subject: [PATCH 07/95] fix dirOffset, expose intersection type to JS --- .../src/raypick/LaserPointerScriptingInterface.cpp | 2 +- interface/src/raypick/RayPickManager.cpp | 8 ++++---- interface/src/raypick/RayPickManager.h | 10 ++++++++++ libraries/shared/src/RegisteredMetaTypes.cpp | 1 + libraries/shared/src/RegisteredMetaTypes.h | 14 +++++++++++--- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index ef87b1780c..68f8423d73 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -34,7 +34,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop glm::vec3 dirOffset = Vectors::UP; if (propertyMap["dirOffset"].isValid()) { - posOffset = vec3FromVariant(propertyMap["dirOffset"]); + dirOffset = vec3FromVariant(propertyMap["dirOffset"]); } uint16_t filter = 0; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index d56d9cb501..c84fbfdd20 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -93,7 +93,7 @@ void RayPickManager::update() { if (!fromCache) { unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); - cacheResult(entityRes.intersects, RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal), + cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal), RayPickMask::PICK_ENTITIES | mask, res, rayKey, results); } } @@ -125,7 +125,7 @@ void RayPickManager::update() { if (!fromCache) { unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); - cacheResult(overlayRes.intersects, RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal), + cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal), RayPickMask::PICK_OVERLAYS | mask, res, rayKey, results); } } @@ -133,7 +133,7 @@ void RayPickManager::update() { if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_AVATARS)) { RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, QScriptValue(), QScriptValue()); - cacheResult(avatarRes.intersects, RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), RayPickMask::PICK_AVATARS, res, rayKey, results); + cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), RayPickMask::PICK_AVATARS, res, rayKey, results); } } @@ -141,7 +141,7 @@ void RayPickManager::update() { if (rayPick->getFilter() & RayPickMask::PICK_HUD && DependencyManager::get()->isHMDMode()) { if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_HUD)) { glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(ray.origin, ray.direction); - cacheResult(true, RayPickResult(0, glm::distance(ray.origin, hudRes), hudRes), RayPickMask::PICK_HUD, res, rayKey, results); + cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes), RayPickMask::PICK_HUD, res, rayKey, results); } } diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 8a98677776..6dc98415e7 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -46,6 +46,11 @@ class RayPickManager : public QObject { Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) public: static RayPickManager& getInstance(); @@ -73,6 +78,11 @@ private: const unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickMask::PICK_INCLUDE_INVISIBLE; } const unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; } const unsigned int PICK_ALL_INTERSECTIONS() { return RayPickMask::PICK_ALL_INTERSECTIONS; } + const unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } + const unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } + const unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } + const unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } + const unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } }; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 1565777666..78b54d26f1 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -755,6 +755,7 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult) { QScriptValue obj = engine->newObject(); + obj.setProperty("type", rayPickResult.type); QScriptValue objectID = quuidToScriptValue(engine, rayPickResult.objectID); obj.setProperty("objectID", objectID); obj.setProperty("distance", rayPickResult.distance); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 7d9ba941a9..f4fc9109ac 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -136,12 +136,20 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); +enum IntersectionType { + NONE, + ENTITY, + OVERLAY, + AVATAR, + HUD +}; + class RayPickResult { public: RayPickResult() {} - RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : - objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) {} - //Type type; + RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + type(type), objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) {} + IntersectionType type { NONE }; QUuid objectID { 0 }; float distance { FLT_MAX }; glm::vec3 intersection { NAN }; From 3c719b26b151afc46deb44edde49cdb68fe7d821 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 13 Jul 2017 17:43:44 -0700 Subject: [PATCH 08/95] working on renderstates --- interface/src/raypick/LaserPointer.cpp | 27 +++++++++--- interface/src/raypick/LaserPointer.h | 30 +++++++++++-- interface/src/raypick/LaserPointerManager.cpp | 5 ++- interface/src/raypick/LaserPointerManager.h | 6 ++- .../LaserPointerScriptingInterface.cpp | 44 +++++++++++++++++-- interface/src/raypick/RayPickManager.cpp | 2 +- 6 files changed, 97 insertions(+), 17 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index b190539607..028b266009 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -13,7 +13,12 @@ #include "RayPickManager.h" #include "JointRayPick.h" -LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) +#include "Application.h" + +LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled) : + _renderingEnabled(enabled), + _renderStates(renderStates) { _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); } @@ -24,16 +29,26 @@ LaserPointer::~LaserPointer() { void LaserPointer::enable() { RayPickManager::getInstance().enableRayPick(_rayPickUID); - // TODO: - // turn on rendering + _renderingEnabled = true; } void LaserPointer::disable() { RayPickManager::getInstance().disableRayPick(_rayPickUID); - // TODO: - // turn off rendering + _renderingEnabled = false; } const RayPickResult& LaserPointer::getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); -} \ No newline at end of file +} + +void LaserPointer::render(RenderArgs* args) { + if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { + _renderStates[_currentRenderState].render(args); + } +} + +void RenderState::render(RenderArgs * args) { + if (!_startID.isNull()) qApp->getOverlays().getOverlay(_startID)->render(args); + if (!_pathID.isNull()) qApp->getOverlays().getOverlay(_pathID)->render(args); + if (!_endID.isNull()) qApp->getOverlays().getOverlay(_endID)->render(args); +} diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index a65c6a9748..f970668bf1 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -13,25 +13,49 @@ #include #include "glm/glm.hpp" +#include +#include "ui/overlays/Overlay.h" class RayPickResult; +class RenderState { + +public: + RenderState() {} + RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) : + _startID(startID), _pathID(pathID), _endID(endID) {} + + void render(RenderArgs* args); + +private: + OverlayID _startID; + OverlayID _pathID; + OverlayID _endID; +}; + + class LaserPointer { public: - LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled); + LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } void enable(); void disable(); - // void setRenderState(const QString& stateName); - // void setRenderStateProperties(const QHash& renderStateProperties); + void setRenderState(const QString& state) { _currentRenderState = state; } const RayPickResult& getPrevRayPickResult(); + void render(RenderArgs* args); + const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); } + private: + bool _renderingEnabled; + QString _currentRenderState { "" }; + QHash _renderStates; unsigned int _rayPickUID; }; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 2e7b084d73..86affdb3b4 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -17,8 +17,9 @@ LaserPointerManager& LaserPointerManager::getInstance() { return instance; } -unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled) { - std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); +unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index f8b3ae1a26..2abe909c01 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -16,7 +16,8 @@ #include #include -class LaserPointer; +#include "LaserPointer.h" + class RayPickResult; class LaserPointerManager { @@ -24,7 +25,8 @@ class LaserPointerManager { public: static LaserPointerManager& getInstance(); - unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, bool enabled); + unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 68f8423d73..a9c096c554 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -15,6 +15,8 @@ #include "RegisteredMetaTypes.h" #include "GLMHelpers.h" +#include "Application.h" + LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { static LaserPointerScriptingInterface instance; return &instance; @@ -52,10 +54,46 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop enabled = propertyMap["enabled"].toBool(); } - // TODO: - // handle render state properties + QHash renderStates; + if (propertyMap["renderStates"].isValid()) { + QList renderStateVariants = propertyMap["renderStates"].toList(); + for (QVariant& renderStateVariant : renderStateVariants) { + if (renderStateVariant.isValid()) { + QVariantMap renderStateMap = renderStateVariant.toMap(); + if (renderStateMap["name"].isValid()) { + QString name = renderStateMap["name"].toString(); - return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, enabled); + QUuid startID; + if (renderStateMap["start"].isValid()) { + QVariantMap startMap = renderStateMap["start"].toMap(); + if (startMap["type"].isValid()) { + startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); + } + } + + QUuid pathID; + if (renderStateMap["path"].isValid()) { + QVariantMap pathMap = renderStateMap["path"].toMap(); + if (pathMap["type"].isValid()) { + pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); + } + } + + QUuid endID; + if (renderStateMap["end"].isValid()) { + QVariantMap endMap = renderStateMap["end"].toMap(); + if (endMap["type"].isValid()) { + endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); + } + } + + renderStates[name] = RenderState(startID, pathID, endID); + } + } + } + } + + return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, enabled); } else { return 0; } diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index c84fbfdd20..33dc16874f 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -49,7 +49,7 @@ void RayPickManager::cacheResult(const bool intersects, const RayPickResult& res void RayPickManager::update() { QHash, QHash> results; - for (auto &rayPick : _rayPicks) { + for (auto& rayPick : _rayPicks) { if (!rayPick->isEnabled() || rayPick->getFilter() == RayPickMask::PICK_NOTHING || rayPick->getMaxDistance() < 0.0f) { continue; } From 8f533636f508626ea3b8bec73a23d92b5d1b374a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 14 Jul 2017 11:13:40 -0700 Subject: [PATCH 09/95] c++ side laserpointer rendering with renderstates --- interface/src/Application.cpp | 5 ++ interface/src/raypick/LaserPointer.cpp | 78 ++++++++++++++++++- interface/src/raypick/LaserPointer.h | 18 ++++- interface/src/raypick/LaserPointerManager.cpp | 12 +++ interface/src/raypick/LaserPointerManager.h | 3 + .../LaserPointerScriptingInterface.cpp | 3 +- .../raypick/LaserPointerScriptingInterface.h | 1 + interface/src/raypick/RayPickManager.cpp | 11 +++ interface/src/raypick/RayPickManager.h | 1 + 9 files changed, 127 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 384484488e..44f15ff16e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4925,6 +4925,11 @@ void Application::update(float deltaTime) { RayPickManager::getInstance().update(); } + { + PROFILE_RANGE(app, "LaserPointerManager"); + LaserPointerManager::getInstance().update(); + } + // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the // loadViewFrumstum() method will get the correct details from the camera diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 028b266009..1e3d6f5126 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -21,10 +21,19 @@ LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, _renderStates(renderStates) { _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); + + if (!enabled) { + disableCurrentRenderState(); + } } LaserPointer::~LaserPointer() { RayPickManager::getInstance().removeRayPick(_rayPickUID); + for (RenderState& renderState : _renderStates) { + if (!renderState.getStartID().isNull()) qApp->getOverlays().deleteOverlay(renderState.getStartID()); + if (!renderState.getPathID().isNull()) qApp->getOverlays().deleteOverlay(renderState.getPathID()); + if (!renderState.getEndID().isNull()) qApp->getOverlays().deleteOverlay(renderState.getEndID()); + } } void LaserPointer::enable() { @@ -35,20 +44,87 @@ void LaserPointer::enable() { void LaserPointer::disable() { RayPickManager::getInstance().disableRayPick(_rayPickUID); _renderingEnabled = false; + if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableCurrentRenderState(); +} + +void LaserPointer::setRenderState(const QString& state) { + if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableCurrentRenderState(); + _currentRenderState = state; } const RayPickResult& LaserPointer::getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } +void LaserPointer::disableCurrentRenderState() { + if (!_renderStates[_currentRenderState].getStartID().isNull()) { + QVariantMap startProps; + startProps.insert("visible", false); + startProps.insert("ignoreRayIntersection", true); + qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getStartID(), startProps); + } + if (!_renderStates[_currentRenderState].getPathID().isNull()) { + QVariantMap pathProps; + pathProps.insert("visible", false); + pathProps.insert("ignoreRayIntersection", true); + qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getPathID(), pathProps); + } + if (!_renderStates[_currentRenderState].getEndID().isNull()) { + QVariantMap endProps; + endProps.insert("visible", false); + endProps.insert("ignoreRayIntersection", true); + qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getEndID(), endProps); + } +} + +void LaserPointer::update() { + RayPickResult prevRayPickResult = RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); + if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState) && prevRayPickResult.type != IntersectionType::NONE) { + PickRay pickRay = RayPickManager::getInstance().getPickRay(_rayPickUID); + if (!_renderStates[_currentRenderState].getStartID().isNull()) { + QVariantMap startProps; + startProps.insert("position", vec3toVariant(pickRay.origin)); + startProps.insert("visible", true); + startProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesStartIgnoreRays()); + qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getStartID(), startProps); + } + QVariant end = vec3toVariant(pickRay.origin + pickRay.direction * prevRayPickResult.distance); + if (!_renderStates[_currentRenderState].getPathID().isNull()) { + QVariantMap pathProps; + pathProps.insert("start", vec3toVariant(pickRay.origin)); + pathProps.insert("end", end); + pathProps.insert("visible", true); + pathProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesPathIgnoreRays()); + qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getPathID(), pathProps); + } + if (!_renderStates[_currentRenderState].getEndID().isNull()) { + QVariantMap endProps; + endProps.insert("position", end); + endProps.insert("visible", true); + endProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesEndIgnoreRays()); + qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getEndID(), endProps); + } + } else { + disableCurrentRenderState(); + } +} + void LaserPointer::render(RenderArgs* args) { if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { _renderStates[_currentRenderState].render(args); } } +RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) : + _startID(startID), _pathID(pathID), _endID(endID) +{ + if (!_startID.isNull()) _startIgnoreRays = qApp->getOverlays().getOverlay(_startID)->getProperty("ignoreRayIntersection").toBool(); + if (!_pathID.isNull()) _pathIgnoreRays = qApp->getOverlays().getOverlay(_pathID)->getProperty("ignoreRayIntersection").toBool(); + if (!_endID.isNull()) _endIgnoreRays = qApp->getOverlays().getOverlay(_endID)->getProperty("ignoreRayIntersection").toBool(); +} + void RenderState::render(RenderArgs * args) { if (!_startID.isNull()) qApp->getOverlays().getOverlay(_startID)->render(args); if (!_pathID.isNull()) qApp->getOverlays().getOverlay(_pathID)->render(args); if (!_endID.isNull()) qApp->getOverlays().getOverlay(_endID)->render(args); -} +} \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index f970668bf1..2910805c74 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -22,15 +22,24 @@ class RenderState { public: RenderState() {} - RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) : - _startID(startID), _pathID(pathID), _endID(endID) {} + RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID); void render(RenderArgs* args); + const OverlayID& getStartID() { return _startID; } + const OverlayID& getPathID() { return _pathID; } + const OverlayID& getEndID() { return _endID; } + const bool& doesStartIgnoreRays() { return _startIgnoreRays; } + const bool& doesPathIgnoreRays() { return _pathIgnoreRays; } + const bool& doesEndIgnoreRays() { return _endIgnoreRays; } + private: OverlayID _startID; OverlayID _pathID; OverlayID _endID; + bool _startIgnoreRays; + bool _pathIgnoreRays; + bool _endIgnoreRays; }; @@ -45,10 +54,13 @@ public: void enable(); void disable(); - void setRenderState(const QString& state) { _currentRenderState = state; } + void setRenderState(const QString& state); const RayPickResult& getPrevRayPickResult(); + void disableCurrentRenderState(); + + void update(); void render(RenderArgs* args); const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); } diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 86affdb3b4..9b4327b647 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -37,9 +37,21 @@ void LaserPointerManager::disableLaserPointer(const unsigned int uid) { } } +void LaserPointerManager::setRenderState(unsigned int uid, const QString & renderState) { + if (_laserPointers.contains(uid)) { + _laserPointers[uid]->setRenderState(renderState); + } +} + const RayPickResult& LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { if (_laserPointers.contains(uid)) { return _laserPointers[uid]->getPrevRayPickResult(); } return RayPickResult(); } + +void LaserPointerManager::update() { + for (auto& laserPointer : _laserPointers) { + laserPointer->update(); + } +} \ No newline at end of file diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 2abe909c01..a9e3215b51 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -30,8 +30,11 @@ public: void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); + void setRenderState(unsigned int uid, const QString& renderState); const RayPickResult& getPrevRayPickResult(const unsigned int uid); + void update(); + private: QHash> _laserPointers; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index a9c096c554..b2848f5463 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -74,7 +74,8 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop QUuid pathID; if (renderStateMap["path"].isValid()) { QVariantMap pathMap = renderStateMap["path"].toMap(); - if (pathMap["type"].isValid()) { + // right now paths must be line3ds + if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); } } diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 8d6758119a..b68a4532db 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -27,6 +27,7 @@ public slots: Q_INVOKABLE void enableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().enableLaserPointer(uid); } Q_INVOKABLE void disableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().disableLaserPointer(uid); } Q_INVOKABLE void removeLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().removeLaserPointer(uid); } + Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) { LaserPointerManager::getInstance().setRenderState(uid, renderState); } Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return LaserPointerManager::getInstance().getPrevRayPickResult(uid); } }; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 33dc16874f..68b979a97a 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -178,6 +178,17 @@ void RayPickManager::disableRayPick(const unsigned int uid) { } } +const PickRay& RayPickManager::getPickRay(const unsigned int uid) { + if (_rayPicks.contains(uid)) { + bool valid; + PickRay pickRay = _rayPicks[uid]->getPickRay(valid); + if (valid) { + return pickRay; + } + } + return PickRay(); +} + const RayPickResult& RayPickManager::getPrevRayPickResult(const unsigned int uid) { // TODO: // does this need to lock the individual ray? what happens with concurrent set/get? diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 6dc98415e7..2af98d171c 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -63,6 +63,7 @@ public: void removeRayPick(const unsigned int uid); void enableRayPick(const unsigned int uid); void disableRayPick(const unsigned int uid); + const PickRay& getPickRay(const unsigned int uid); const RayPickResult& getPrevRayPickResult(const unsigned int uid); private: From af12b5a4bfeb5895a910985e009f005022bb5d1f Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 14 Jul 2017 18:35:27 -0700 Subject: [PATCH 10/95] can create static laser pointers, fixed a bug with multiple render states --- interface/src/raypick/LaserPointer.cpp | 51 ++++---- interface/src/raypick/LaserPointer.h | 13 +- interface/src/raypick/LaserPointerManager.cpp | 7 + interface/src/raypick/LaserPointerManager.h | 2 + .../LaserPointerScriptingInterface.cpp | 123 ++++++++++-------- 5 files changed, 106 insertions(+), 90 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 1e3d6f5126..b480d64374 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -12,6 +12,7 @@ #include "RayPickManager.h" #include "JointRayPick.h" +#include "StaticRayPick.h" #include "Application.h" @@ -22,8 +23,22 @@ LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, { _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); - if (!enabled) { - disableCurrentRenderState(); + for (auto& state : _renderStates.keys()) { + if (!enabled || state != _currentRenderState) + disableRenderState(state); + } +} + +LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled) : + _renderingEnabled(enabled), + _renderStates(renderStates) +{ + _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(position, direction, filter, maxDistance, enabled)); + + for (auto& state : _renderStates.keys()) { + if (!enabled || state != _currentRenderState) + disableRenderState(state); } } @@ -44,11 +59,11 @@ void LaserPointer::enable() { void LaserPointer::disable() { RayPickManager::getInstance().disableRayPick(_rayPickUID); _renderingEnabled = false; - if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableCurrentRenderState(); + if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableRenderState(_currentRenderState); } void LaserPointer::setRenderState(const QString& state) { - if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableCurrentRenderState(); + if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableRenderState(_currentRenderState); _currentRenderState = state; } @@ -56,24 +71,24 @@ const RayPickResult& LaserPointer::getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } -void LaserPointer::disableCurrentRenderState() { - if (!_renderStates[_currentRenderState].getStartID().isNull()) { +void LaserPointer::disableRenderState(const QString& renderState) { + if (!_renderStates[renderState].getStartID().isNull()) { QVariantMap startProps; startProps.insert("visible", false); startProps.insert("ignoreRayIntersection", true); - qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getStartID(), startProps); + qApp->getOverlays().editOverlay(_renderStates[renderState].getStartID(), startProps); } - if (!_renderStates[_currentRenderState].getPathID().isNull()) { + if (!_renderStates[renderState].getPathID().isNull()) { QVariantMap pathProps; pathProps.insert("visible", false); pathProps.insert("ignoreRayIntersection", true); - qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getPathID(), pathProps); + qApp->getOverlays().editOverlay(_renderStates[renderState].getPathID(), pathProps); } - if (!_renderStates[_currentRenderState].getEndID().isNull()) { + if (!_renderStates[renderState].getEndID().isNull()) { QVariantMap endProps; endProps.insert("visible", false); endProps.insert("ignoreRayIntersection", true); - qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getEndID(), endProps); + qApp->getOverlays().editOverlay(_renderStates[renderState].getEndID(), endProps); } } @@ -105,13 +120,7 @@ void LaserPointer::update() { qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getEndID(), endProps); } } else { - disableCurrentRenderState(); - } -} - -void LaserPointer::render(RenderArgs* args) { - if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { - _renderStates[_currentRenderState].render(args); + disableRenderState(_currentRenderState); } } @@ -121,10 +130,4 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons if (!_startID.isNull()) _startIgnoreRays = qApp->getOverlays().getOverlay(_startID)->getProperty("ignoreRayIntersection").toBool(); if (!_pathID.isNull()) _pathIgnoreRays = qApp->getOverlays().getOverlay(_pathID)->getProperty("ignoreRayIntersection").toBool(); if (!_endID.isNull()) _endIgnoreRays = qApp->getOverlays().getOverlay(_endID)->getProperty("ignoreRayIntersection").toBool(); -} - -void RenderState::render(RenderArgs * args) { - if (!_startID.isNull()) qApp->getOverlays().getOverlay(_startID)->render(args); - if (!_pathID.isNull()) qApp->getOverlays().getOverlay(_pathID)->render(args); - if (!_endID.isNull()) qApp->getOverlays().getOverlay(_endID)->render(args); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 2910805c74..ef834d8190 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -13,7 +13,6 @@ #include #include "glm/glm.hpp" -#include #include "ui/overlays/Overlay.h" class RayPickResult; @@ -24,8 +23,6 @@ public: RenderState() {} RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID); - void render(RenderArgs* args); - const OverlayID& getStartID() { return _startID; } const OverlayID& getPathID() { return _pathID; } const OverlayID& getEndID() { return _endID; } @@ -48,21 +45,19 @@ class LaserPointer { public: LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool enabled); + LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } void enable(); void disable(); - - void setRenderState(const QString& state); - const RayPickResult& getPrevRayPickResult(); - void disableCurrentRenderState(); + void setRenderState(const QString& state); + void disableRenderState(const QString& renderState); void update(); - void render(RenderArgs* args); - const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); } private: bool _renderingEnabled; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 9b4327b647..3d0aa1f4b1 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -25,6 +25,13 @@ unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, c return uid; } +unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, enabled); + unsigned int uid = laserPointer->getUID(); + _laserPointers[uid] = laserPointer; + return uid; +} + void LaserPointerManager::enableLaserPointer(const unsigned int uid) { if (_laserPointers.contains(uid)) { _laserPointers[uid]->enable(); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index a9e3215b51..f9b59e3bb5 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -27,6 +27,8 @@ public: unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool enabled); + unsigned int createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index b2848f5463..48bbdb5278 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -25,6 +25,61 @@ LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { QVariantMap propertyMap = properties.toMap(); + uint16_t filter = 0; + if (propertyMap["filter"].isValid()) { + filter = propertyMap["filter"].toUInt(); + } + + float maxDistance = 0.0f; + if (propertyMap["maxDistance"].isValid()) { + maxDistance = propertyMap["maxDistance"].toFloat(); + } + + bool enabled = false; + if (propertyMap["enabled"].isValid()) { + enabled = propertyMap["enabled"].toBool(); + } + + QHash renderStates; + if (propertyMap["renderStates"].isValid()) { + QList renderStateVariants = propertyMap["renderStates"].toList(); + for (QVariant& renderStateVariant : renderStateVariants) { + if (renderStateVariant.isValid()) { + QVariantMap renderStateMap = renderStateVariant.toMap(); + if (renderStateMap["name"].isValid()) { + QString name = renderStateMap["name"].toString(); + + QUuid startID; + if (renderStateMap["start"].isValid()) { + QVariantMap startMap = renderStateMap["start"].toMap(); + if (startMap["type"].isValid()) { + startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); + } + } + + QUuid pathID; + if (renderStateMap["path"].isValid()) { + QVariantMap pathMap = renderStateMap["path"].toMap(); + // right now paths must be line3ds + if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { + pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); + } + } + + QUuid endID; + if (renderStateMap["end"].isValid()) { + QVariantMap endMap = renderStateMap["end"].toMap(); + if (endMap["type"].isValid()) { + endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); + } + } + + renderStates[name] = RenderState(startID, pathID, endID); + } + } + } + } + if (propertyMap["joint"].isValid()) { QString jointName = propertyMap["joint"].toString(); @@ -39,63 +94,17 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop dirOffset = vec3FromVariant(propertyMap["dirOffset"]); } - uint16_t filter = 0; - if (propertyMap["filter"].isValid()) { - filter = propertyMap["filter"].toUInt(); - } - - float maxDistance = 0.0f; - if (propertyMap["maxDistance"].isValid()) { - maxDistance = propertyMap["maxDistance"].toFloat(); - } - - bool enabled = false; - if (propertyMap["enabled"].isValid()) { - enabled = propertyMap["enabled"].toBool(); - } - - QHash renderStates; - if (propertyMap["renderStates"].isValid()) { - QList renderStateVariants = propertyMap["renderStates"].toList(); - for (QVariant& renderStateVariant : renderStateVariants) { - if (renderStateVariant.isValid()) { - QVariantMap renderStateMap = renderStateVariant.toMap(); - if (renderStateMap["name"].isValid()) { - QString name = renderStateMap["name"].toString(); - - QUuid startID; - if (renderStateMap["start"].isValid()) { - QVariantMap startMap = renderStateMap["start"].toMap(); - if (startMap["type"].isValid()) { - startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); - } - } - - QUuid pathID; - if (renderStateMap["path"].isValid()) { - QVariantMap pathMap = renderStateMap["path"].toMap(); - // right now paths must be line3ds - if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { - pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); - } - } - - QUuid endID; - if (renderStateMap["end"].isValid()) { - QVariantMap endMap = renderStateMap["end"].toMap(); - if (endMap["type"].isValid()) { - endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); - } - } - - renderStates[name] = RenderState(startID, pathID, endID); - } - } - } - } - return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, enabled); - } else { - return 0; + } else if (propertyMap["position"].isValid()) { + glm::vec3 position = vec3FromVariant(propertyMap["position"]); + + glm::vec3 direction = -Vectors::UP; + if (propertyMap["direction"].isValid()) { + direction = vec3FromVariant(propertyMap["direction"]); + } + + return LaserPointerManager::getInstance().createLaserPointer(position, direction, filter, maxDistance, renderStates, enabled); } + + return 0; } \ No newline at end of file From ae99be0350a65038a3260e495d69486bfb82d413 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 17 Jul 2017 13:07:42 -0700 Subject: [PATCH 11/95] added faceAvatar and centerEndY, working on updating teleport.js, style fixes --- interface/src/raypick/LaserPointer.cpp | 72 ++- interface/src/raypick/LaserPointer.h | 10 +- interface/src/raypick/LaserPointerManager.cpp | 11 +- interface/src/raypick/LaserPointerManager.h | 6 +- .../LaserPointerScriptingInterface.cpp | 14 +- interface/src/raypick/RayPickManager.cpp | 4 +- interface/src/raypick/RayPickManager.h | 4 +- scripts/system/controllers/old_teleport.js | 538 ++++++++++++++++++ scripts/system/controllers/teleport.js | 284 ++++----- 9 files changed, 740 insertions(+), 203 deletions(-) create mode 100644 scripts/system/controllers/old_teleport.js diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index b480d64374..ed5fbd2ece 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -10,44 +10,56 @@ // #include "LaserPointer.h" -#include "RayPickManager.h" #include "JointRayPick.h" #include "StaticRayPick.h" #include "Application.h" +#include "avatar/AvatarManager.h" LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled) : + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) : _renderingEnabled(enabled), - _renderStates(renderStates) + _renderStates(renderStates), + _faceAvatar(faceAvatar), + _centerEndY(centerEndY) { _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); for (auto& state : _renderStates.keys()) { - if (!enabled || state != _currentRenderState) - disableRenderState(state); + if (!enabled || state != _currentRenderState) { + disableRenderState(state); + } } } LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled) : + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) : _renderingEnabled(enabled), - _renderStates(renderStates) + _renderStates(renderStates), + _faceAvatar(faceAvatar), + _centerEndY(centerEndY) { _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(position, direction, filter, maxDistance, enabled)); for (auto& state : _renderStates.keys()) { - if (!enabled || state != _currentRenderState) + if (!enabled || state != _currentRenderState) { disableRenderState(state); + } } } LaserPointer::~LaserPointer() { RayPickManager::getInstance().removeRayPick(_rayPickUID); for (RenderState& renderState : _renderStates) { - if (!renderState.getStartID().isNull()) qApp->getOverlays().deleteOverlay(renderState.getStartID()); - if (!renderState.getPathID().isNull()) qApp->getOverlays().deleteOverlay(renderState.getPathID()); - if (!renderState.getEndID().isNull()) qApp->getOverlays().deleteOverlay(renderState.getEndID()); + if (!renderState.getStartID().isNull()) { + qApp->getOverlays().deleteOverlay(renderState.getStartID()); + } + if (!renderState.getPathID().isNull()) { + qApp->getOverlays().deleteOverlay(renderState.getPathID()); + } + if (!renderState.getEndID().isNull()) { + qApp->getOverlays().deleteOverlay(renderState.getEndID()); + } } } @@ -59,18 +71,18 @@ void LaserPointer::enable() { void LaserPointer::disable() { RayPickManager::getInstance().disableRayPick(_rayPickUID); _renderingEnabled = false; - if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableRenderState(_currentRenderState); + if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { + disableRenderState(_currentRenderState); + } } void LaserPointer::setRenderState(const QString& state) { - if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) disableRenderState(_currentRenderState); + if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { + disableRenderState(_currentRenderState); + } _currentRenderState = state; } -const RayPickResult& LaserPointer::getPrevRayPickResult() { - return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); -} - void LaserPointer::disableRenderState(const QString& renderState) { if (!_renderStates[renderState].getStartID().isNull()) { QVariantMap startProps; @@ -103,7 +115,8 @@ void LaserPointer::update() { startProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesStartIgnoreRays()); qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getStartID(), startProps); } - QVariant end = vec3toVariant(pickRay.origin + pickRay.direction * prevRayPickResult.distance); + glm::vec3 endVec = pickRay.origin + pickRay.direction * prevRayPickResult.distance; + QVariant end = vec3toVariant(endVec); if (!_renderStates[_currentRenderState].getPathID().isNull()) { QVariantMap pathProps; pathProps.insert("start", vec3toVariant(pickRay.origin)); @@ -114,7 +127,16 @@ void LaserPointer::update() { } if (!_renderStates[_currentRenderState].getEndID().isNull()) { QVariantMap endProps; - endProps.insert("position", end); + if (_centerEndY) { + endProps.insert("position", end); + } else { + glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(_renderStates[_currentRenderState].getEndID(), "dimensions").value); + endProps.insert("position", vec3toVariant(endVec + glm::vec3(0, 0.5f * dim.y, 0))); + } + if (_faceAvatar) { + glm::quat rotation = glm::inverse(glm::quat_cast(glm::lookAt(endVec, DependencyManager::get()->getMyAvatar()->getPosition(), Vectors::UP))); + endProps.insert("rotation", quatToVariant(glm::quat(glm::radians(glm::vec3(0, glm::degrees(safeEulerAngles(rotation)).y, 0))))); + } endProps.insert("visible", true); endProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesEndIgnoreRays()); qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getEndID(), endProps); @@ -127,7 +149,13 @@ void LaserPointer::update() { RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) : _startID(startID), _pathID(pathID), _endID(endID) { - if (!_startID.isNull()) _startIgnoreRays = qApp->getOverlays().getOverlay(_startID)->getProperty("ignoreRayIntersection").toBool(); - if (!_pathID.isNull()) _pathIgnoreRays = qApp->getOverlays().getOverlay(_pathID)->getProperty("ignoreRayIntersection").toBool(); - if (!_endID.isNull()) _endIgnoreRays = qApp->getOverlays().getOverlay(_endID)->getProperty("ignoreRayIntersection").toBool(); + if (!_startID.isNull()) { + _startIgnoreRays = qApp->getOverlays().getOverlay(_startID)->getProperty("ignoreRayIntersection").toBool(); + } + if (!_pathID.isNull()) { + _pathIgnoreRays = qApp->getOverlays().getOverlay(_pathID)->getProperty("ignoreRayIntersection").toBool(); + } + if (!_endID.isNull()) { + _endIgnoreRays = qApp->getOverlays().getOverlay(_endID)->getProperty("ignoreRayIntersection").toBool(); + } } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index ef834d8190..23f3f2a943 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -14,6 +14,7 @@ #include #include "glm/glm.hpp" #include "ui/overlays/Overlay.h" +#include "RayPickManager.h" class RayPickResult; @@ -44,15 +45,15 @@ class LaserPointer { public: LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } void enable(); void disable(); - const RayPickResult& getPrevRayPickResult(); + const RayPickResult& getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } void setRenderState(const QString& state); void disableRenderState(const QString& renderState); @@ -63,6 +64,9 @@ private: bool _renderingEnabled; QString _currentRenderState { "" }; QHash _renderStates; + bool _faceAvatar; + bool _centerEndY; + unsigned int _rayPickUID; }; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 3d0aa1f4b1..e4c9e18127 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -18,15 +18,16 @@ LaserPointerManager& LaserPointerManager::getInstance() { } unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; } -unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, enabled); +unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; @@ -50,7 +51,7 @@ void LaserPointerManager::setRenderState(unsigned int uid, const QString & rende } } -const RayPickResult& LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { +const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { if (_laserPointers.contains(uid)) { return _laserPointers[uid]->getPrevRayPickResult(); } diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index f9b59e3bb5..09423bd18a 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -26,14 +26,14 @@ public: static LaserPointerManager& getInstance(); unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); unsigned int createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); void setRenderState(unsigned int uid, const QString& renderState); - const RayPickResult& getPrevRayPickResult(const unsigned int uid); + const RayPickResult getPrevRayPickResult(const unsigned int uid); void update(); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 48bbdb5278..cf0289c44b 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -35,6 +35,16 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop maxDistance = propertyMap["maxDistance"].toFloat(); } + bool faceAvatar = false; + if (propertyMap["faceAvatar"].isValid()) { + faceAvatar = propertyMap["faceAvatar"].toBool(); + } + + bool centerEndY = true; + if (propertyMap["centerEndY"].isValid()) { + centerEndY = propertyMap["centerEndY"].toBool(); + } + bool enabled = false; if (propertyMap["enabled"].isValid()) { enabled = propertyMap["enabled"].toBool(); @@ -94,7 +104,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop dirOffset = vec3FromVariant(propertyMap["dirOffset"]); } - return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, enabled); + return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); } else if (propertyMap["position"].isValid()) { glm::vec3 position = vec3FromVariant(propertyMap["position"]); @@ -103,7 +113,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop direction = vec3FromVariant(propertyMap["direction"]); } - return LaserPointerManager::getInstance().createLaserPointer(position, direction, filter, maxDistance, renderStates, enabled); + return LaserPointerManager::getInstance().createLaserPointer(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); } return 0; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 68b979a97a..5f1c5add7b 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -178,7 +178,7 @@ void RayPickManager::disableRayPick(const unsigned int uid) { } } -const PickRay& RayPickManager::getPickRay(const unsigned int uid) { +const PickRay RayPickManager::getPickRay(const unsigned int uid) { if (_rayPicks.contains(uid)) { bool valid; PickRay pickRay = _rayPicks[uid]->getPickRay(valid); @@ -189,7 +189,7 @@ const PickRay& RayPickManager::getPickRay(const unsigned int uid) { return PickRay(); } -const RayPickResult& RayPickManager::getPrevRayPickResult(const unsigned int uid) { +const RayPickResult RayPickManager::getPrevRayPickResult(const unsigned int uid) { // TODO: // does this need to lock the individual ray? what happens with concurrent set/get? if (_rayPicks.contains(uid)) { diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 2af98d171c..d798e8a742 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -63,8 +63,8 @@ public: void removeRayPick(const unsigned int uid); void enableRayPick(const unsigned int uid); void disableRayPick(const unsigned int uid); - const PickRay& getPickRay(const unsigned int uid); - const RayPickResult& getPrevRayPickResult(const unsigned int uid); + const PickRay getPickRay(const unsigned int uid); + const RayPickResult getPrevRayPickResult(const unsigned int uid); private: QHash> _rayPicks; diff --git a/scripts/system/controllers/old_teleport.js b/scripts/system/controllers/old_teleport.js new file mode 100644 index 0000000000..b058ec670f --- /dev/null +++ b/scripts/system/controllers/old_teleport.js @@ -0,0 +1,538 @@ +"use strict"; + +// Created by james b. pollack @imgntn on 7/2/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Creates a beam and target and then teleports you there. Release when its close to you to cancel. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +(function() { // BEGIN LOCAL_SCOPE + +var inTeleportMode = false; + +var SMOOTH_ARRIVAL_SPACING = 33; +var NUMBER_OF_STEPS = 6; + +var TARGET_MODEL_URL = Script.resolvePath("../assets/models/teleport-destination.fbx"); +var TOO_CLOSE_MODEL_URL = Script.resolvePath("../assets/models/teleport-cancel.fbx"); +var SEAT_MODEL_URL = Script.resolvePath("../assets/models/teleport-seat.fbx"); + +var TARGET_MODEL_DIMENSIONS = { + x: 1.15, + y: 0.5, + z: 1.15 +}; + +var COLORS_TELEPORT_SEAT = { + red: 255, + green: 0, + blue: 170 +}; + +var COLORS_TELEPORT_CAN_TELEPORT = { + red: 97, + green: 247, + blue: 255 +}; + +var COLORS_TELEPORT_CANNOT_TELEPORT = { + red: 0, + green: 121, + blue: 141 +}; + +var COLORS_TELEPORT_CANCEL = { + red: 255, + green: 184, + blue: 73 +}; + +var TELEPORT_CANCEL_RANGE = 1; +var COOL_IN_DURATION = 500; + +var handInfo = { + right: { + controllerInput: Controller.Standard.RightHand + }, + left: { + controllerInput: Controller.Standard.LeftHand + } +}; + +function ThumbPad(hand) { + this.hand = hand; + var _thisPad = this; + + this.buttonPress = function(value) { + _thisPad.buttonValue = value; + }; +} + +function Trigger(hand) { + this.hand = hand; + var _this = this; + + this.buttonPress = function(value) { + _this.buttonValue = value; + }; + + this.down = function() { + var down = _this.buttonValue === 1 ? 1.0 : 0.0; + return down; + }; +} + +var coolInTimeout = null; +var ignoredEntities = []; + +var TELEPORTER_STATES = { + IDLE: 'idle', + COOL_IN: 'cool_in', + TARGETTING: 'targetting', + TARGETTING_INVALID: 'targetting_invalid', +}; + +var TARGET = { + NONE: 'none', // Not currently targetting anything + INVISIBLE: 'invisible', // The current target is an invvsible surface + INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) + SURFACE: 'surface', // The current target is a valid surface + SEAT: 'seat', // The current target is a seat +}; + +function Teleporter() { + var _this = this; + this.active = false; + this.state = TELEPORTER_STATES.IDLE; + this.currentTarget = TARGET.INVALID; + + this.overlayLines = { + left: null, + right: null, + }; + this.updateConnected = null; + this.activeHand = null; + + this.teleporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random(); + this.teleportMappingInternal = Controller.newMapping(this.teleporterMappingInternalName); + + // Setup overlays + this.cancelOverlay = Overlays.addOverlay("model", { + url: TOO_CLOSE_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + visible: false + }); + this.targetOverlay = Overlays.addOverlay("model", { + url: TARGET_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + visible: false + }); + this.seatOverlay = Overlays.addOverlay("model", { + url: SEAT_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + visible: false + }); + + this.enableMappings = function() { + Controller.enableMapping(this.teleporterMappingInternalName); + }; + + this.disableMappings = function() { + Controller.disableMapping(teleporter.teleporterMappingInternalName); + }; + + this.cleanup = function() { + this.disableMappings(); + + Overlays.deleteOverlay(this.targetOverlay); + this.targetOverlay = null; + + Overlays.deleteOverlay(this.cancelOverlay); + this.cancelOverlay = null; + + Overlays.deleteOverlay(this.seatOverlay); + this.seatOverlay = null; + + this.deleteOverlayBeams(); + if (this.updateConnected === true) { + Script.update.disconnect(this, this.update); + } + }; + + this.enterTeleportMode = function(hand) { + if (inTeleportMode === true) { + return; + } + if (isDisabled === 'both' || isDisabled === hand) { + return; + } + + inTeleportMode = true; + + if (coolInTimeout !== null) { + Script.clearTimeout(coolInTimeout); + } + + this.state = TELEPORTER_STATES.COOL_IN; + coolInTimeout = Script.setTimeout(function() { + if (_this.state === TELEPORTER_STATES.COOL_IN) { + _this.state = TELEPORTER_STATES.TARGETTING; + } + }, COOL_IN_DURATION); + + this.activeHand = hand; + this.enableMappings(); + Script.update.connect(this, this.update); + this.updateConnected = true; + }; + + this.exitTeleportMode = function(value) { + if (this.updateConnected === true) { + Script.update.disconnect(this, this.update); + } + + this.disableMappings(); + this.deleteOverlayBeams(); + this.hideTargetOverlay(); + this.hideCancelOverlay(); + + this.updateConnected = null; + this.state = TELEPORTER_STATES.IDLE; + inTeleportMode = false; + }; + + this.deleteOverlayBeams = function() { + for (var key in this.overlayLines) { + if (this.overlayLines[key] !== null) { + Overlays.deleteOverlay(this.overlayLines[key]); + this.overlayLines[key] = null; + } + } + }; + + this.update = function() { + if (_this.state === TELEPORTER_STATES.IDLE) { + return; + } + + // Get current hand pose information so that we can get the direction of the teleport beam + var pose = Controller.getPoseValue(handInfo[_this.activeHand].controllerInput); + var handPosition = pose.valid ? Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) : MyAvatar.getHeadPosition(); + var handRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) : + Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + })); + + var pickRay = { + origin: handPosition, + direction: Quat.getUp(handRotation), + }; + + // We do up to 2 ray picks to find a teleport location. + // There are 2 types of teleport locations we are interested in: + // 1. A visible floor. This can be any entity surface that points within some degree of "up" + // 2. A seat. The seat can be visible or invisible. + // + // * In the first pass we pick against visible and invisible entities so that we can find invisible seats. + // We might hit an invisible entity that is not a seat, so we need to do a second pass. + // * In the second pass we pick against visible entities only. + // + var intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), false, true); + + var teleportLocationType = getTeleportTargetType(intersection); + if (teleportLocationType === TARGET.INVISIBLE) { + intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), true, true); + teleportLocationType = getTeleportTargetType(intersection); + } + + if (teleportLocationType === TARGET.NONE) { + this.hideTargetOverlay(); + this.hideCancelOverlay(); + this.hideSeatOverlay(); + + var farPosition = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, 50)); + this.updateLineOverlay(_this.activeHand, pickRay.origin, farPosition, COLORS_TELEPORT_CANNOT_TELEPORT); + } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { + this.hideTargetOverlay(); + this.hideSeatOverlay(); + + this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CANCEL); + this.updateDestinationOverlay(this.cancelOverlay, intersection); + } else if (teleportLocationType === TARGET.SURFACE) { + if (this.state === TELEPORTER_STATES.COOL_IN) { + this.hideTargetOverlay(); + this.hideSeatOverlay(); + + this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CANCEL); + this.updateDestinationOverlay(this.cancelOverlay, intersection); + } else { + this.hideCancelOverlay(); + this.hideSeatOverlay(); + + this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, + COLORS_TELEPORT_CAN_TELEPORT); + this.updateDestinationOverlay(this.targetOverlay, intersection); + } + } else if (teleportLocationType === TARGET.SEAT) { + this.hideCancelOverlay(); + this.hideTargetOverlay(); + + this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_SEAT); + this.updateDestinationOverlay(this.seatOverlay, intersection); + } + + + if (((_this.activeHand === 'left' ? leftPad : rightPad).buttonValue === 0) && inTeleportMode === true) { + // remember the state before we exit teleport mode and set it back to IDLE + var previousState = this.state; + this.exitTeleportMode(); + this.hideCancelOverlay(); + this.hideTargetOverlay(); + this.hideSeatOverlay(); + + if (teleportLocationType === TARGET.NONE || teleportLocationType === TARGET.INVALID || previousState === TELEPORTER_STATES.COOL_IN) { + // Do nothing + } else if (teleportLocationType === TARGET.SEAT) { + Entities.callEntityMethod(intersection.entityID, 'sit'); + } else if (teleportLocationType === TARGET.SURFACE) { + var offset = getAvatarFootOffset(); + intersection.intersection.y += offset; + MyAvatar.goToLocation(intersection.intersection, false, {x: 0, y: 0, z: 0, w: 1}, false); + HMD.centerUI(); + MyAvatar.centerBody(); + } + } + }; + + this.updateLineOverlay = function(hand, closePoint, farPoint, color) { + if (this.overlayLines[hand] === null) { + var lineProperties = { + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, + visible: true, + alpha: 1, + solid: true, + drawInFront: true, + glow: 1.0 + }; + + this.overlayLines[hand] = Overlays.addOverlay("line3d", lineProperties); + + } else { + Overlays.editOverlay(this.overlayLines[hand], { + start: closePoint, + end: farPoint, + color: color + }); + } + }; + + this.hideCancelOverlay = function() { + Overlays.editOverlay(this.cancelOverlay, { visible: false }); + }; + + this.hideTargetOverlay = function() { + Overlays.editOverlay(this.targetOverlay, { visible: false }); + }; + + this.hideSeatOverlay = function() { + Overlays.editOverlay(this.seatOverlay, { visible: false }); + }; + + this.updateDestinationOverlay = function(overlayID, intersection) { + var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP); + var euler = Quat.safeEulerAngles(rotation); + var position = { + x: intersection.intersection.x, + y: intersection.intersection.y + TARGET_MODEL_DIMENSIONS.y / 2, + z: intersection.intersection.z + }; + + var towardUs = Quat.fromPitchYawRollDegrees(0, euler.y, 0); + + Overlays.editOverlay(overlayID, { + visible: true, + position: position, + rotation: towardUs + }); + + }; +} + +// related to repositioning the avatar after you teleport +var FOOT_JOINT_NAMES = ["RightToe_End", "RightToeBase", "RightFoot"]; +var DEFAULT_ROOT_TO_FOOT_OFFSET = 0.5; +function getAvatarFootOffset() { + + // find a valid foot jointIndex + var footJointIndex = -1; + var i, l = FOOT_JOINT_NAMES.length; + for (i = 0; i < l; i++) { + footJointIndex = MyAvatar.getJointIndex(FOOT_JOINT_NAMES[i]); + if (footJointIndex != -1) { + break; + } + } + if (footJointIndex != -1) { + // default vertical offset from foot to avatar root. + return -MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(footJointIndex).y; + } else { + return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale; + } +} + +var leftPad = new ThumbPad('left'); +var rightPad = new ThumbPad('right'); +var leftTrigger = new Trigger('left'); +var rightTrigger = new Trigger('right'); + +var mappingName, teleportMapping; + +var TELEPORT_DELAY = 0; + +function isMoving() { + var LY = Controller.getValue(Controller.Standard.LY); + var LX = Controller.getValue(Controller.Standard.LX); + if (LY !== 0 || LX !== 0) { + return true; + } else { + return false; + } +} + +function parseJSON(json) { + try { + return JSON.parse(json); + } catch (e) { + return undefined; + } +} +// When determininig whether you can teleport to a location, the normal of the +// point that is being intersected with is looked at. If this normal is more +// than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from <0, 1, 0> (straight up), then +// you can't teleport there. +var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; +function getTeleportTargetType(intersection) { + if (!intersection.intersects) { + return TARGET.NONE; + } + + var props = Entities.getEntityProperties(intersection.entityID, ['userData', 'visible']); + var data = parseJSON(props.userData); + if (data !== undefined && data.seat !== undefined) { + var avatarUuid = Uuid.fromString(data.seat.user); + if (Uuid.isNull(avatarUuid) || !AvatarList.getAvatar(avatarUuid)) { + return TARGET.SEAT; + } else { + return TARGET.INVALID; + } + } + + if (!props.visible) { + return TARGET.INVISIBLE; + } + + var surfaceNormal = intersection.surfaceNormal; + var adj = Math.sqrt(surfaceNormal.x * surfaceNormal.x + surfaceNormal.z * surfaceNormal.z); + var angleUp = Math.atan2(surfaceNormal.y, adj) * (180 / Math.PI); + + if (angleUp < (90 - MAX_ANGLE_FROM_UP_TO_TELEPORT) || + angleUp > (90 + MAX_ANGLE_FROM_UP_TO_TELEPORT) || + Vec3.distance(MyAvatar.position, intersection.intersection) <= TELEPORT_CANCEL_RANGE) { + return TARGET.INVALID; + } else { + return TARGET.SURFACE; + } +} + +function registerMappings() { + mappingName = 'Hifi-Teleporter-Dev-' + Math.random(); + teleportMapping = Controller.newMapping(mappingName); + teleportMapping.from(Controller.Standard.RT).peek().to(rightTrigger.buttonPress); + teleportMapping.from(Controller.Standard.LT).peek().to(leftTrigger.buttonPress); + + teleportMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(rightPad.buttonPress); + teleportMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(leftPad.buttonPress); + + teleportMapping.from(Controller.Standard.LeftPrimaryThumb) + .to(function(value) { + if (isDisabled === 'left' || isDisabled === 'both') { + return; + } + if (leftTrigger.down()) { + return; + } + if (isMoving() === true) { + return; + } + teleporter.enterTeleportMode('left'); + return; + }); + teleportMapping.from(Controller.Standard.RightPrimaryThumb) + .to(function(value) { + if (isDisabled === 'right' || isDisabled === 'both') { + return; + } + if (rightTrigger.down()) { + return; + } + if (isMoving() === true) { + return; + } + + teleporter.enterTeleportMode('right'); + return; + }); +} + +registerMappings(); + +var teleporter = new Teleporter(); + +Controller.enableMapping(mappingName); + +function cleanup() { + teleportMapping.disable(); + teleporter.cleanup(); +} +Script.scriptEnding.connect(cleanup); + +var isDisabled = false; +var handleTeleportMessages = function(channel, message, sender) { + if (sender === MyAvatar.sessionUUID) { + if (channel === 'Hifi-Teleport-Disabler') { + if (message === 'both') { + isDisabled = 'both'; + } + if (message === 'left') { + isDisabled = 'left'; + } + if (message === 'right') { + isDisabled = 'right'; + } + if (message === 'none') { + isDisabled = false; + } + } else if (channel === 'Hifi-Teleport-Ignore-Add' && !Uuid.isNull(message) && ignoredEntities.indexOf(message) === -1) { + ignoredEntities.push(message); + } else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) { + var removeIndex = ignoredEntities.indexOf(message); + if (removeIndex > -1) { + ignoredEntities.splice(removeIndex, 1); + } + } + } +}; + +Messages.subscribe('Hifi-Teleport-Disabler'); +Messages.subscribe('Hifi-Teleport-Ignore-Add'); +Messages.subscribe('Hifi-Teleport-Ignore-Remove'); +Messages.messageReceived.connect(handleTeleportMessages); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index b058ec670f..b72828ea6b 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -37,12 +37,6 @@ var COLORS_TELEPORT_CAN_TELEPORT = { blue: 255 }; -var COLORS_TELEPORT_CANNOT_TELEPORT = { - red: 0, - green: 121, - blue: 141 -}; - var COLORS_TELEPORT_CANCEL = { red: 255, green: 184, @@ -52,14 +46,55 @@ var COLORS_TELEPORT_CANCEL = { var TELEPORT_CANCEL_RANGE = 1; var COOL_IN_DURATION = 500; -var handInfo = { - right: { - controllerInput: Controller.Standard.RightHand - }, - left: { - controllerInput: Controller.Standard.LeftHand - } +var cancelPath = { + type: "line3d", + color: COLORS_TELEPORT_CANCEL, + ignoreRayIntersection: true, + alpha: 1, + solid: true, + drawInFront: true, + glow: 1.0 }; +var teleportPath = { + type: "line3d", + color: COLORS_TELEPORT_CAN_TELEPORT, + ignoreRayIntersection: true, + alpha: 1, + solid: true, + drawInFront: true, + glow: 1.0 +}; +var seatPath = { + type: "line3d", + color: COLORS_TELEPORT_SEAT, + ignoreRayIntersection: true, + alpha: 1, + solid: true, + drawInFront: true, + glow: 1.0 +}; +var cancelEnd = { + type: "model", + url: TOO_CLOSE_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + ignoreRayIntersection: true +}; +var teleportEnd = { + type: "model", + url: TARGET_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + ignoreRayIntersection: true +}; +var seatEnd = { + type: "model", + url: SEAT_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + ignoreRayIntersection: true +} + +var teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd}, + {name: "teleport", path: teleportPath, end: teleportEnd}, + {name: "seat", path: seatPath, end: seatEnd}]; function ThumbPad(hand) { this.hand = hand; @@ -108,33 +143,41 @@ function Teleporter() { this.state = TELEPORTER_STATES.IDLE; this.currentTarget = TARGET.INVALID; - this.overlayLines = { - left: null, - right: null, - }; + this.teleportRayLeftVisible = LaserPointers.createLaserPointer({ + joint: "LeftHand", + filter: RayPick.PICK_ENTITIES, + faceAvatar: true, + centerEndY: false, + renderStates: teleportRenderStates + }); + this.teleportRayLeftInvisible = LaserPointers.createLaserPointer({ + joint: "LeftHand", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + centerEndY: false, + renderStates: teleportRenderStates + }); + this.teleportRayRightVisible = LaserPointers.createLaserPointer({ + joint: "RightHand", + filter: RayPick.PICK_ENTITIES, + faceAvatar: true, + centerEndY: false, + renderStates: teleportRenderStates + }); + this.teleportRayRightInvisible = LaserPointers.createLaserPointer({ + joint: "RightHand", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + centerEndY: false, + renderStates: teleportRenderStates + }); + this.updateConnected = null; this.activeHand = null; this.teleporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random(); this.teleportMappingInternal = Controller.newMapping(this.teleporterMappingInternalName); - // Setup overlays - this.cancelOverlay = Overlays.addOverlay("model", { - url: TOO_CLOSE_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: false - }); - this.targetOverlay = Overlays.addOverlay("model", { - url: TARGET_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: false - }); - this.seatOverlay = Overlays.addOverlay("model", { - url: SEAT_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: false - }); - this.enableMappings = function() { Controller.enableMapping(this.teleporterMappingInternalName); }; @@ -146,16 +189,11 @@ function Teleporter() { this.cleanup = function() { this.disableMappings(); - Overlays.deleteOverlay(this.targetOverlay); - this.targetOverlay = null; + LaserPointers.removeLaserPointer(this.teleportRayLeftVisible); + LaserPointers.removeLaserPointer(this.teleportRayLeftInvisible); + LaserPointers.removeLaserPointer(this.teleportRayRightVisible); + LaserPointers.removeLaserPointer(this.teleportRayRightInvisible); - Overlays.deleteOverlay(this.cancelOverlay); - this.cancelOverlay = null; - - Overlays.deleteOverlay(this.seatOverlay); - this.seatOverlay = null; - - this.deleteOverlayBeams(); if (this.updateConnected === true) { Script.update.disconnect(this, this.update); } @@ -175,6 +213,14 @@ function Teleporter() { Script.clearTimeout(coolInTimeout); } + if (hand === 'right') { + LaserPointers.enableLaserPointer(_this.teleportRayRightVisible); + LaserPointers.enableLaserPointer(_this.teleportRayRightInvisible); + } else { + LaserPointers.enableLaserPointer(_this.teleportRayLeftVisible); + LaserPointers.enableLaserPointer(_this.teleportRayLeftInvisible); + } + this.state = TELEPORTER_STATES.COOL_IN; coolInTimeout = Script.setTimeout(function() { if (_this.state === TELEPORTER_STATES.COOL_IN) { @@ -194,44 +240,21 @@ function Teleporter() { } this.disableMappings(); - this.deleteOverlayBeams(); - this.hideTargetOverlay(); - this.hideCancelOverlay(); + LaserPointers.disableLaserPointer(this.teleportRayLeftVisible); + LaserPointers.disableLaserPointer(this.teleportRayLeftInvisible); + LaserPointers.disableLaserPointer(this.teleportRayRightVisible); + LaserPointers.disableLaserPointer(this.teleportRayRightInvisible); this.updateConnected = null; this.state = TELEPORTER_STATES.IDLE; inTeleportMode = false; }; - this.deleteOverlayBeams = function() { - for (var key in this.overlayLines) { - if (this.overlayLines[key] !== null) { - Overlays.deleteOverlay(this.overlayLines[key]); - this.overlayLines[key] = null; - } - } - }; - this.update = function() { if (_this.state === TELEPORTER_STATES.IDLE) { return; } - // Get current hand pose information so that we can get the direction of the teleport beam - var pose = Controller.getPoseValue(handInfo[_this.activeHand].controllerInput); - var handPosition = pose.valid ? Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) : MyAvatar.getHeadPosition(); - var handRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) : - Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - })); - - var pickRay = { - origin: handPosition, - direction: Quat.getUp(handRotation), - }; - // We do up to 2 ray picks to find a teleport location. // There are 2 types of teleport locations we are interested in: // 1. A visible floor. This can be any entity surface that points within some degree of "up" @@ -241,48 +264,28 @@ function Teleporter() { // We might hit an invisible entity that is not a seat, so we need to do a second pass. // * In the second pass we pick against visible entities only. // - var intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), false, true); + var result = (_this.activeHand === 'right') ? LaserPointers.getPrevRayPickResult(_this.teleportRayRightInvisible) : + LaserPointers.getPrevRayPickResult(_this.teleportRayLeftInvisible); - var teleportLocationType = getTeleportTargetType(intersection); + var teleportLocationType = getTeleportTargetType(result); if (teleportLocationType === TARGET.INVISIBLE) { - intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), true, true); - teleportLocationType = getTeleportTargetType(intersection); + result = (_this.activeHand === 'right') ? LaserPointers.getPrevRayPickResult(_this.teleportRayRightVisible) : + LaserPointers.getPrevRayPickResult(_this.teleportRayLeftVisible); + teleportLocationType = getTeleportTargetType(result); } if (teleportLocationType === TARGET.NONE) { - this.hideTargetOverlay(); - this.hideCancelOverlay(); - this.hideSeatOverlay(); - - var farPosition = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, 50)); - this.updateLineOverlay(_this.activeHand, pickRay.origin, farPosition, COLORS_TELEPORT_CANNOT_TELEPORT); + this.setTeleportState(_this.activeHand, "", ""); } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { - this.hideTargetOverlay(); - this.hideSeatOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CANCEL); - this.updateDestinationOverlay(this.cancelOverlay, intersection); + this.setTeleportState(_this.activeHand, "", "cancel"); } else if (teleportLocationType === TARGET.SURFACE) { if (this.state === TELEPORTER_STATES.COOL_IN) { - this.hideTargetOverlay(); - this.hideSeatOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CANCEL); - this.updateDestinationOverlay(this.cancelOverlay, intersection); + this.setTeleportState(_this.activeHand, "cancel", ""); } else { - this.hideCancelOverlay(); - this.hideSeatOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, - COLORS_TELEPORT_CAN_TELEPORT); - this.updateDestinationOverlay(this.targetOverlay, intersection); + this.setTeleportState(_this.activeHand, "teleport", ""); } } else if (teleportLocationType === TARGET.SEAT) { - this.hideCancelOverlay(); - this.hideTargetOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_SEAT); - this.updateDestinationOverlay(this.seatOverlay, intersection); + this.setTeleportState(_this.activeHand, "", "seat"); } @@ -290,79 +293,30 @@ function Teleporter() { // remember the state before we exit teleport mode and set it back to IDLE var previousState = this.state; this.exitTeleportMode(); - this.hideCancelOverlay(); - this.hideTargetOverlay(); - this.hideSeatOverlay(); if (teleportLocationType === TARGET.NONE || teleportLocationType === TARGET.INVALID || previousState === TELEPORTER_STATES.COOL_IN) { // Do nothing } else if (teleportLocationType === TARGET.SEAT) { - Entities.callEntityMethod(intersection.entityID, 'sit'); + Entities.callEntityMethod(result.objectID, 'sit'); } else if (teleportLocationType === TARGET.SURFACE) { var offset = getAvatarFootOffset(); - intersection.intersection.y += offset; - MyAvatar.goToLocation(intersection.intersection, false, {x: 0, y: 0, z: 0, w: 1}, false); + result.intersection.y += offset; + MyAvatar.goToLocation(result.intersection, false, {x: 0, y: 0, z: 0, w: 1}, false); HMD.centerUI(); MyAvatar.centerBody(); } } }; - this.updateLineOverlay = function(hand, closePoint, farPoint, color) { - if (this.overlayLines[hand] === null) { - var lineProperties = { - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, - visible: true, - alpha: 1, - solid: true, - drawInFront: true, - glow: 1.0 - }; - - this.overlayLines[hand] = Overlays.addOverlay("line3d", lineProperties); - + this.setTeleportState = function(hand, visibleState, invisibleState) { + if (hand === 'right') { + LaserPointers.setRenderState(_this.teleportRayRightVisible, visibleState); + LaserPointers.setRenderState(_this.teleportRayRightInvisible, invisibleState); } else { - Overlays.editOverlay(this.overlayLines[hand], { - start: closePoint, - end: farPoint, - color: color - }); + LaserPointers.setRenderState(_this.teleportRayLeftVisible, visibleState); + LaserPointers.setRenderState(_this.teleportRayLeftInvisible, invisibleState); } }; - - this.hideCancelOverlay = function() { - Overlays.editOverlay(this.cancelOverlay, { visible: false }); - }; - - this.hideTargetOverlay = function() { - Overlays.editOverlay(this.targetOverlay, { visible: false }); - }; - - this.hideSeatOverlay = function() { - Overlays.editOverlay(this.seatOverlay, { visible: false }); - }; - - this.updateDestinationOverlay = function(overlayID, intersection) { - var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP); - var euler = Quat.safeEulerAngles(rotation); - var position = { - x: intersection.intersection.x, - y: intersection.intersection.y + TARGET_MODEL_DIMENSIONS.y / 2, - z: intersection.intersection.z - }; - - var towardUs = Quat.fromPitchYawRollDegrees(0, euler.y, 0); - - Overlays.editOverlay(overlayID, { - visible: true, - position: position, - rotation: towardUs - }); - - }; } // related to repositioning the avatar after you teleport @@ -418,12 +372,12 @@ function parseJSON(json) { // than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from <0, 1, 0> (straight up), then // you can't teleport there. var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; -function getTeleportTargetType(intersection) { - if (!intersection.intersects) { +function getTeleportTargetType(result) { + if (result.type == RayPick.INTERSECTED_NONE) { return TARGET.NONE; } - var props = Entities.getEntityProperties(intersection.entityID, ['userData', 'visible']); + var props = Entities.getEntityProperties(result.objectID, ['userData', 'visible']); var data = parseJSON(props.userData); if (data !== undefined && data.seat !== undefined) { var avatarUuid = Uuid.fromString(data.seat.user); @@ -438,13 +392,13 @@ function getTeleportTargetType(intersection) { return TARGET.INVISIBLE; } - var surfaceNormal = intersection.surfaceNormal; + var surfaceNormal = result.surfaceNormal; var adj = Math.sqrt(surfaceNormal.x * surfaceNormal.x + surfaceNormal.z * surfaceNormal.z); var angleUp = Math.atan2(surfaceNormal.y, adj) * (180 / Math.PI); if (angleUp < (90 - MAX_ANGLE_FROM_UP_TO_TELEPORT) || angleUp > (90 + MAX_ANGLE_FROM_UP_TO_TELEPORT) || - Vec3.distance(MyAvatar.position, intersection.intersection) <= TELEPORT_CANCEL_RANGE) { + Vec3.distance(MyAvatar.position, result.intersection) <= TELEPORT_CANCEL_RANGE) { return TARGET.INVALID; } else { return TARGET.SURFACE; @@ -520,6 +474,8 @@ var handleTeleportMessages = function(channel, message, sender) { isDisabled = false; } } else if (channel === 'Hifi-Teleport-Ignore-Add' && !Uuid.isNull(message) && ignoredEntities.indexOf(message) === -1) { + // TODO: + // add ability to ignore entities to LaserPointers ignoredEntities.push(message); } else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) { var removeIndex = ignoredEntities.indexOf(message); From 197ba83b103ab1caf74d2905b8936d87df8e838d Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 17 Jul 2017 13:46:23 -0700 Subject: [PATCH 12/95] remove old_teleport --- scripts/system/controllers/old_teleport.js | 538 --------------------- 1 file changed, 538 deletions(-) delete mode 100644 scripts/system/controllers/old_teleport.js diff --git a/scripts/system/controllers/old_teleport.js b/scripts/system/controllers/old_teleport.js deleted file mode 100644 index b058ec670f..0000000000 --- a/scripts/system/controllers/old_teleport.js +++ /dev/null @@ -1,538 +0,0 @@ -"use strict"; - -// Created by james b. pollack @imgntn on 7/2/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Creates a beam and target and then teleports you there. Release when its close to you to cancel. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -(function() { // BEGIN LOCAL_SCOPE - -var inTeleportMode = false; - -var SMOOTH_ARRIVAL_SPACING = 33; -var NUMBER_OF_STEPS = 6; - -var TARGET_MODEL_URL = Script.resolvePath("../assets/models/teleport-destination.fbx"); -var TOO_CLOSE_MODEL_URL = Script.resolvePath("../assets/models/teleport-cancel.fbx"); -var SEAT_MODEL_URL = Script.resolvePath("../assets/models/teleport-seat.fbx"); - -var TARGET_MODEL_DIMENSIONS = { - x: 1.15, - y: 0.5, - z: 1.15 -}; - -var COLORS_TELEPORT_SEAT = { - red: 255, - green: 0, - blue: 170 -}; - -var COLORS_TELEPORT_CAN_TELEPORT = { - red: 97, - green: 247, - blue: 255 -}; - -var COLORS_TELEPORT_CANNOT_TELEPORT = { - red: 0, - green: 121, - blue: 141 -}; - -var COLORS_TELEPORT_CANCEL = { - red: 255, - green: 184, - blue: 73 -}; - -var TELEPORT_CANCEL_RANGE = 1; -var COOL_IN_DURATION = 500; - -var handInfo = { - right: { - controllerInput: Controller.Standard.RightHand - }, - left: { - controllerInput: Controller.Standard.LeftHand - } -}; - -function ThumbPad(hand) { - this.hand = hand; - var _thisPad = this; - - this.buttonPress = function(value) { - _thisPad.buttonValue = value; - }; -} - -function Trigger(hand) { - this.hand = hand; - var _this = this; - - this.buttonPress = function(value) { - _this.buttonValue = value; - }; - - this.down = function() { - var down = _this.buttonValue === 1 ? 1.0 : 0.0; - return down; - }; -} - -var coolInTimeout = null; -var ignoredEntities = []; - -var TELEPORTER_STATES = { - IDLE: 'idle', - COOL_IN: 'cool_in', - TARGETTING: 'targetting', - TARGETTING_INVALID: 'targetting_invalid', -}; - -var TARGET = { - NONE: 'none', // Not currently targetting anything - INVISIBLE: 'invisible', // The current target is an invvsible surface - INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) - SURFACE: 'surface', // The current target is a valid surface - SEAT: 'seat', // The current target is a seat -}; - -function Teleporter() { - var _this = this; - this.active = false; - this.state = TELEPORTER_STATES.IDLE; - this.currentTarget = TARGET.INVALID; - - this.overlayLines = { - left: null, - right: null, - }; - this.updateConnected = null; - this.activeHand = null; - - this.teleporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random(); - this.teleportMappingInternal = Controller.newMapping(this.teleporterMappingInternalName); - - // Setup overlays - this.cancelOverlay = Overlays.addOverlay("model", { - url: TOO_CLOSE_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: false - }); - this.targetOverlay = Overlays.addOverlay("model", { - url: TARGET_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: false - }); - this.seatOverlay = Overlays.addOverlay("model", { - url: SEAT_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: false - }); - - this.enableMappings = function() { - Controller.enableMapping(this.teleporterMappingInternalName); - }; - - this.disableMappings = function() { - Controller.disableMapping(teleporter.teleporterMappingInternalName); - }; - - this.cleanup = function() { - this.disableMappings(); - - Overlays.deleteOverlay(this.targetOverlay); - this.targetOverlay = null; - - Overlays.deleteOverlay(this.cancelOverlay); - this.cancelOverlay = null; - - Overlays.deleteOverlay(this.seatOverlay); - this.seatOverlay = null; - - this.deleteOverlayBeams(); - if (this.updateConnected === true) { - Script.update.disconnect(this, this.update); - } - }; - - this.enterTeleportMode = function(hand) { - if (inTeleportMode === true) { - return; - } - if (isDisabled === 'both' || isDisabled === hand) { - return; - } - - inTeleportMode = true; - - if (coolInTimeout !== null) { - Script.clearTimeout(coolInTimeout); - } - - this.state = TELEPORTER_STATES.COOL_IN; - coolInTimeout = Script.setTimeout(function() { - if (_this.state === TELEPORTER_STATES.COOL_IN) { - _this.state = TELEPORTER_STATES.TARGETTING; - } - }, COOL_IN_DURATION); - - this.activeHand = hand; - this.enableMappings(); - Script.update.connect(this, this.update); - this.updateConnected = true; - }; - - this.exitTeleportMode = function(value) { - if (this.updateConnected === true) { - Script.update.disconnect(this, this.update); - } - - this.disableMappings(); - this.deleteOverlayBeams(); - this.hideTargetOverlay(); - this.hideCancelOverlay(); - - this.updateConnected = null; - this.state = TELEPORTER_STATES.IDLE; - inTeleportMode = false; - }; - - this.deleteOverlayBeams = function() { - for (var key in this.overlayLines) { - if (this.overlayLines[key] !== null) { - Overlays.deleteOverlay(this.overlayLines[key]); - this.overlayLines[key] = null; - } - } - }; - - this.update = function() { - if (_this.state === TELEPORTER_STATES.IDLE) { - return; - } - - // Get current hand pose information so that we can get the direction of the teleport beam - var pose = Controller.getPoseValue(handInfo[_this.activeHand].controllerInput); - var handPosition = pose.valid ? Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) : MyAvatar.getHeadPosition(); - var handRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) : - Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - })); - - var pickRay = { - origin: handPosition, - direction: Quat.getUp(handRotation), - }; - - // We do up to 2 ray picks to find a teleport location. - // There are 2 types of teleport locations we are interested in: - // 1. A visible floor. This can be any entity surface that points within some degree of "up" - // 2. A seat. The seat can be visible or invisible. - // - // * In the first pass we pick against visible and invisible entities so that we can find invisible seats. - // We might hit an invisible entity that is not a seat, so we need to do a second pass. - // * In the second pass we pick against visible entities only. - // - var intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), false, true); - - var teleportLocationType = getTeleportTargetType(intersection); - if (teleportLocationType === TARGET.INVISIBLE) { - intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), true, true); - teleportLocationType = getTeleportTargetType(intersection); - } - - if (teleportLocationType === TARGET.NONE) { - this.hideTargetOverlay(); - this.hideCancelOverlay(); - this.hideSeatOverlay(); - - var farPosition = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, 50)); - this.updateLineOverlay(_this.activeHand, pickRay.origin, farPosition, COLORS_TELEPORT_CANNOT_TELEPORT); - } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { - this.hideTargetOverlay(); - this.hideSeatOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CANCEL); - this.updateDestinationOverlay(this.cancelOverlay, intersection); - } else if (teleportLocationType === TARGET.SURFACE) { - if (this.state === TELEPORTER_STATES.COOL_IN) { - this.hideTargetOverlay(); - this.hideSeatOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CANCEL); - this.updateDestinationOverlay(this.cancelOverlay, intersection); - } else { - this.hideCancelOverlay(); - this.hideSeatOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, - COLORS_TELEPORT_CAN_TELEPORT); - this.updateDestinationOverlay(this.targetOverlay, intersection); - } - } else if (teleportLocationType === TARGET.SEAT) { - this.hideCancelOverlay(); - this.hideTargetOverlay(); - - this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_SEAT); - this.updateDestinationOverlay(this.seatOverlay, intersection); - } - - - if (((_this.activeHand === 'left' ? leftPad : rightPad).buttonValue === 0) && inTeleportMode === true) { - // remember the state before we exit teleport mode and set it back to IDLE - var previousState = this.state; - this.exitTeleportMode(); - this.hideCancelOverlay(); - this.hideTargetOverlay(); - this.hideSeatOverlay(); - - if (teleportLocationType === TARGET.NONE || teleportLocationType === TARGET.INVALID || previousState === TELEPORTER_STATES.COOL_IN) { - // Do nothing - } else if (teleportLocationType === TARGET.SEAT) { - Entities.callEntityMethod(intersection.entityID, 'sit'); - } else if (teleportLocationType === TARGET.SURFACE) { - var offset = getAvatarFootOffset(); - intersection.intersection.y += offset; - MyAvatar.goToLocation(intersection.intersection, false, {x: 0, y: 0, z: 0, w: 1}, false); - HMD.centerUI(); - MyAvatar.centerBody(); - } - } - }; - - this.updateLineOverlay = function(hand, closePoint, farPoint, color) { - if (this.overlayLines[hand] === null) { - var lineProperties = { - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, - visible: true, - alpha: 1, - solid: true, - drawInFront: true, - glow: 1.0 - }; - - this.overlayLines[hand] = Overlays.addOverlay("line3d", lineProperties); - - } else { - Overlays.editOverlay(this.overlayLines[hand], { - start: closePoint, - end: farPoint, - color: color - }); - } - }; - - this.hideCancelOverlay = function() { - Overlays.editOverlay(this.cancelOverlay, { visible: false }); - }; - - this.hideTargetOverlay = function() { - Overlays.editOverlay(this.targetOverlay, { visible: false }); - }; - - this.hideSeatOverlay = function() { - Overlays.editOverlay(this.seatOverlay, { visible: false }); - }; - - this.updateDestinationOverlay = function(overlayID, intersection) { - var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP); - var euler = Quat.safeEulerAngles(rotation); - var position = { - x: intersection.intersection.x, - y: intersection.intersection.y + TARGET_MODEL_DIMENSIONS.y / 2, - z: intersection.intersection.z - }; - - var towardUs = Quat.fromPitchYawRollDegrees(0, euler.y, 0); - - Overlays.editOverlay(overlayID, { - visible: true, - position: position, - rotation: towardUs - }); - - }; -} - -// related to repositioning the avatar after you teleport -var FOOT_JOINT_NAMES = ["RightToe_End", "RightToeBase", "RightFoot"]; -var DEFAULT_ROOT_TO_FOOT_OFFSET = 0.5; -function getAvatarFootOffset() { - - // find a valid foot jointIndex - var footJointIndex = -1; - var i, l = FOOT_JOINT_NAMES.length; - for (i = 0; i < l; i++) { - footJointIndex = MyAvatar.getJointIndex(FOOT_JOINT_NAMES[i]); - if (footJointIndex != -1) { - break; - } - } - if (footJointIndex != -1) { - // default vertical offset from foot to avatar root. - return -MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(footJointIndex).y; - } else { - return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale; - } -} - -var leftPad = new ThumbPad('left'); -var rightPad = new ThumbPad('right'); -var leftTrigger = new Trigger('left'); -var rightTrigger = new Trigger('right'); - -var mappingName, teleportMapping; - -var TELEPORT_DELAY = 0; - -function isMoving() { - var LY = Controller.getValue(Controller.Standard.LY); - var LX = Controller.getValue(Controller.Standard.LX); - if (LY !== 0 || LX !== 0) { - return true; - } else { - return false; - } -} - -function parseJSON(json) { - try { - return JSON.parse(json); - } catch (e) { - return undefined; - } -} -// When determininig whether you can teleport to a location, the normal of the -// point that is being intersected with is looked at. If this normal is more -// than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from <0, 1, 0> (straight up), then -// you can't teleport there. -var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; -function getTeleportTargetType(intersection) { - if (!intersection.intersects) { - return TARGET.NONE; - } - - var props = Entities.getEntityProperties(intersection.entityID, ['userData', 'visible']); - var data = parseJSON(props.userData); - if (data !== undefined && data.seat !== undefined) { - var avatarUuid = Uuid.fromString(data.seat.user); - if (Uuid.isNull(avatarUuid) || !AvatarList.getAvatar(avatarUuid)) { - return TARGET.SEAT; - } else { - return TARGET.INVALID; - } - } - - if (!props.visible) { - return TARGET.INVISIBLE; - } - - var surfaceNormal = intersection.surfaceNormal; - var adj = Math.sqrt(surfaceNormal.x * surfaceNormal.x + surfaceNormal.z * surfaceNormal.z); - var angleUp = Math.atan2(surfaceNormal.y, adj) * (180 / Math.PI); - - if (angleUp < (90 - MAX_ANGLE_FROM_UP_TO_TELEPORT) || - angleUp > (90 + MAX_ANGLE_FROM_UP_TO_TELEPORT) || - Vec3.distance(MyAvatar.position, intersection.intersection) <= TELEPORT_CANCEL_RANGE) { - return TARGET.INVALID; - } else { - return TARGET.SURFACE; - } -} - -function registerMappings() { - mappingName = 'Hifi-Teleporter-Dev-' + Math.random(); - teleportMapping = Controller.newMapping(mappingName); - teleportMapping.from(Controller.Standard.RT).peek().to(rightTrigger.buttonPress); - teleportMapping.from(Controller.Standard.LT).peek().to(leftTrigger.buttonPress); - - teleportMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(rightPad.buttonPress); - teleportMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(leftPad.buttonPress); - - teleportMapping.from(Controller.Standard.LeftPrimaryThumb) - .to(function(value) { - if (isDisabled === 'left' || isDisabled === 'both') { - return; - } - if (leftTrigger.down()) { - return; - } - if (isMoving() === true) { - return; - } - teleporter.enterTeleportMode('left'); - return; - }); - teleportMapping.from(Controller.Standard.RightPrimaryThumb) - .to(function(value) { - if (isDisabled === 'right' || isDisabled === 'both') { - return; - } - if (rightTrigger.down()) { - return; - } - if (isMoving() === true) { - return; - } - - teleporter.enterTeleportMode('right'); - return; - }); -} - -registerMappings(); - -var teleporter = new Teleporter(); - -Controller.enableMapping(mappingName); - -function cleanup() { - teleportMapping.disable(); - teleporter.cleanup(); -} -Script.scriptEnding.connect(cleanup); - -var isDisabled = false; -var handleTeleportMessages = function(channel, message, sender) { - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Hifi-Teleport-Disabler') { - if (message === 'both') { - isDisabled = 'both'; - } - if (message === 'left') { - isDisabled = 'left'; - } - if (message === 'right') { - isDisabled = 'right'; - } - if (message === 'none') { - isDisabled = false; - } - } else if (channel === 'Hifi-Teleport-Ignore-Add' && !Uuid.isNull(message) && ignoredEntities.indexOf(message) === -1) { - ignoredEntities.push(message); - } else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) { - var removeIndex = ignoredEntities.indexOf(message); - if (removeIndex > -1) { - ignoredEntities.splice(removeIndex, 1); - } - } - } -}; - -Messages.subscribe('Hifi-Teleport-Disabler'); -Messages.subscribe('Hifi-Teleport-Ignore-Add'); -Messages.subscribe('Hifi-Teleport-Ignore-Remove'); -Messages.messageReceived.connect(handleTeleportMessages); - -}()); // END LOCAL_SCOPE From 7084a0607ab7d17fb488dd29d18343a9bcde7d1a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 17 Jul 2017 14:26:22 -0700 Subject: [PATCH 13/95] fix warnings --- interface/src/raypick/JointRayPick.h | 2 +- interface/src/raypick/LaserPointer.h | 4 +-- interface/src/raypick/LaserPointerManager.h | 2 +- .../raypick/LaserPointerScriptingInterface.h | 2 +- interface/src/raypick/RayPick.h | 8 +++--- interface/src/raypick/RayPickManager.h | 28 +++++++++---------- interface/src/raypick/StaticRayPick.h | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index 54d393ab46..99ffb14f01 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -29,4 +29,4 @@ private: }; -#endif hifi_JointRayPick_h \ No newline at end of file +#endif hifi_JointRayPick_h diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 23f3f2a943..d0e28f59d0 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -53,7 +53,7 @@ public: unsigned int getUID() { return _rayPickUID; } void enable(); void disable(); - const RayPickResult& getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } + const RayPickResult getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } void setRenderState(const QString& state); void disableRenderState(const QString& renderState); @@ -70,4 +70,4 @@ private: unsigned int _rayPickUID; }; -#endif hifi_LaserPointer_h \ No newline at end of file +#endif hifi_LaserPointer_h diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 09423bd18a..427568c87c 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -42,4 +42,4 @@ private: }; -#endif hifi_LaserPointerManager_h \ No newline at end of file +#endif hifi_LaserPointerManager_h diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index b68a4532db..19298cffd9 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -32,4 +32,4 @@ public slots: }; -#endif hifi_LaserPointerScriptingInterface_h \ No newline at end of file +#endif hifi_LaserPointerScriptingInterface_h diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 855cd53ba8..72fea450aa 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -24,9 +24,9 @@ public: void enable() { _enabled = true; } void disable() { _enabled = false; } - const uint16_t getFilter() { return _filter; } - const float getMaxDistance() { return _maxDistance; } - const bool isEnabled() { return _enabled; } + const uint16_t& getFilter() { return _filter; } + const float& getMaxDistance() { return _maxDistance; } + const bool& isEnabled() { return _enabled; } const RayPickResult& getPrevRayPickResult() { return _prevResult; } void setRayPickResult(const RayPickResult& rayPickResult) { _prevResult = rayPickResult; } @@ -39,4 +39,4 @@ private: }; -#endif hifi_RayPick_h \ No newline at end of file +#endif hifi_RayPick_h diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index d798e8a742..80f28572b1 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -70,20 +70,20 @@ private: QHash> _rayPicks; unsigned int _nextUID { 1 }; // 0 is invalid - const unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } - const unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } - const unsigned int PICK_OVERLAYS() { return RayPickMask::PICK_OVERLAYS; } - const unsigned int PICK_AVATARS() { return RayPickMask::PICK_AVATARS; } - const unsigned int PICK_HUD() { return RayPickMask::PICK_HUD; } - const unsigned int PICK_BOUNDING_BOX() { return RayPickMask::PICK_BOUNDING_BOX; } - const unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickMask::PICK_INCLUDE_INVISIBLE; } - const unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; } - const unsigned int PICK_ALL_INTERSECTIONS() { return RayPickMask::PICK_ALL_INTERSECTIONS; } - const unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } - const unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } - const unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } - const unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } - const unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } + unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } + unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } + unsigned int PICK_OVERLAYS() { return RayPickMask::PICK_OVERLAYS; } + unsigned int PICK_AVATARS() { return RayPickMask::PICK_AVATARS; } + unsigned int PICK_HUD() { return RayPickMask::PICK_HUD; } + unsigned int PICK_BOUNDING_BOX() { return RayPickMask::PICK_BOUNDING_BOX; } + unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickMask::PICK_INCLUDE_INVISIBLE; } + unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; } + unsigned int PICK_ALL_INTERSECTIONS() { return RayPickMask::PICK_ALL_INTERSECTIONS; } + unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } + unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } + unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } + unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } + unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } }; diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index f4f2b769e3..c2e418164e 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -25,4 +25,4 @@ private: }; -#endif hifi_StaticRayPick_h \ No newline at end of file +#endif hifi_StaticRayPick_h From 0c8c6ff5d677abe7b9ba5792920a9c286ec3702d Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 17 Jul 2017 15:05:31 -0700 Subject: [PATCH 14/95] silly me --- interface/src/raypick/JointRayPick.h | 2 +- interface/src/raypick/LaserPointer.h | 2 +- interface/src/raypick/LaserPointerManager.h | 2 +- interface/src/raypick/LaserPointerScriptingInterface.h | 2 +- interface/src/raypick/RayPick.h | 2 +- interface/src/raypick/RayPickManager.h | 2 +- interface/src/raypick/StaticRayPick.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index 99ffb14f01..8b57583238 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -29,4 +29,4 @@ private: }; -#endif hifi_JointRayPick_h +#endif // hifi_JointRayPick_h diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index d0e28f59d0..075ec5e7f7 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -70,4 +70,4 @@ private: unsigned int _rayPickUID; }; -#endif hifi_LaserPointer_h +#endif // hifi_LaserPointer_h diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 427568c87c..f5a8484054 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -42,4 +42,4 @@ private: }; -#endif hifi_LaserPointerManager_h +#endif // hifi_LaserPointerManager_h diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 19298cffd9..b16daedda6 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -32,4 +32,4 @@ public slots: }; -#endif hifi_LaserPointerScriptingInterface_h +#endif // hifi_LaserPointerScriptingInterface_h diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 72fea450aa..26d09ab8a8 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -39,4 +39,4 @@ private: }; -#endif hifi_RayPick_h +#endif // hifi_RayPick_h diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 80f28572b1..12d12de30d 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -87,4 +87,4 @@ private: }; -#endif hifi_RayPickManager_h \ No newline at end of file +#endif // hifi_RayPickManager_h \ No newline at end of file diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index c2e418164e..6e2fe89e8c 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -25,4 +25,4 @@ private: }; -#endif hifi_StaticRayPick_h +#endif // hifi_StaticRayPick_h From 298faa9f0fe0a5f3bc47bacda6c681d129aaf8bf Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 18 Jul 2017 12:13:16 -0700 Subject: [PATCH 15/95] threading pass --- interface/src/raypick/JointRayPick.cpp | 2 +- interface/src/raypick/JointRayPick.h | 2 +- interface/src/raypick/RayPick.h | 2 +- interface/src/raypick/RayPickManager.cpp | 44 ++++++++++++++++++------ interface/src/raypick/RayPickManager.h | 8 +++++ interface/src/raypick/StaticRayPick.cpp | 2 +- interface/src/raypick/StaticRayPick.h | 2 +- 7 files changed, 47 insertions(+), 15 deletions(-) diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index 9309f0d826..3281d307d9 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -21,7 +21,7 @@ JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, { } -const PickRay JointRayPick::getPickRay(bool& valid) { +const PickRay JointRayPick::getPickRay(bool& valid) const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(_jointName); if (jointIndex != -1) { diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index 8b57583238..0631372bdb 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -20,7 +20,7 @@ class JointRayPick : public RayPick { public: JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) override; + const PickRay getPickRay(bool& valid) const override; private: QString _jointName; diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 26d09ab8a8..e149611210 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -19,7 +19,7 @@ class RayPick { public: RayPick(const uint16_t filter, const float maxDistance, const bool enabled); - virtual const PickRay getPickRay(bool& valid) = 0; + virtual const PickRay getPickRay(bool& valid) const = 0; void enable() { _enabled = true; } void disable() { _enabled = false; } diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 5f1c5add7b..8ca503114c 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -49,7 +49,8 @@ void RayPickManager::cacheResult(const bool intersects, const RayPickResult& res void RayPickManager::update() { QHash, QHash> results; - for (auto& rayPick : _rayPicks) { + for (auto& uid : _rayPicks.keys()) { + std::shared_ptr rayPick = _rayPicks[uid]; if (!rayPick->isEnabled() || rayPick->getFilter() == RayPickMask::PICK_NOTHING || rayPick->getMaxDistance() < 0.0f) { continue; } @@ -145,40 +146,63 @@ void RayPickManager::update() { } } - if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { + QWriteLocker lock(_rayPickLocks[uid].get()); + if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { rayPick->setRayPickResult(res); } else { rayPick->setRayPickResult(RayPickResult()); } } + + QWriteLocker containsLock(&_containsLock); + { + QWriteLocker lock(&_addLock); + while (!_rayPicksToAdd.isEmpty()) { + QPair> rayPickToAdd = _rayPicksToAdd.dequeue(); + _rayPicks[rayPickToAdd.first] = rayPickToAdd.second; + _rayPickLocks[rayPickToAdd.first] = std::make_shared(); + } + } + + { + QWriteLocker lock(&_removeLock); + while (!_rayPicksToRemove.isEmpty()) { + unsigned int uid = _rayPicksToRemove.dequeue(); + _rayPicks.remove(uid); + _rayPickLocks.remove(uid); + } + } } unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { - // TODO: - // use lock and defer adding to prevent issues - _rayPicks[_nextUID] = rayPick; + QWriteLocker lock(&_addLock); + _rayPicksToAdd.enqueue(QPair>(_nextUID, rayPick)); return _nextUID++; } void RayPickManager::removeRayPick(const unsigned int uid) { - // TODO: - // use lock and defer removing to prevent issues - _rayPicks.remove(uid); + QWriteLocker lock(&_removeLock); + _rayPicksToRemove.enqueue(uid); } void RayPickManager::enableRayPick(const unsigned int uid) { + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { + QWriteLocker rayPickLock(_rayPickLocks[uid].get()); _rayPicks[uid]->enable(); } } void RayPickManager::disableRayPick(const unsigned int uid) { + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { + QWriteLocker rayPickLock(_rayPickLocks[uid].get()); _rayPicks[uid]->disable(); } } const PickRay RayPickManager::getPickRay(const unsigned int uid) { + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { bool valid; PickRay pickRay = _rayPicks[uid]->getPickRay(valid); @@ -190,9 +214,9 @@ const PickRay RayPickManager::getPickRay(const unsigned int uid) { } const RayPickResult RayPickManager::getPrevRayPickResult(const unsigned int uid) { - // TODO: - // does this need to lock the individual ray? what happens with concurrent set/get? + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { + QReadLocker lock(_rayPickLocks[uid].get()); return _rayPicks[uid]->getPrevRayPickResult(); } return RayPickResult(); diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 12d12de30d..ad4fb3f286 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -14,6 +14,8 @@ #include "RegisteredMetaTypes.h" #include +#include +#include #include #include @@ -68,7 +70,13 @@ public: private: QHash> _rayPicks; + QHash> _rayPickLocks; unsigned int _nextUID { 1 }; // 0 is invalid + QReadWriteLock _addLock; + QQueue>> _rayPicksToAdd; + QReadWriteLock _removeLock; + QQueue _rayPicksToRemove; + QReadWriteLock _containsLock; unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } diff --git a/interface/src/raypick/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp index 9edd992a17..43088150ad 100644 --- a/interface/src/raypick/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -16,7 +16,7 @@ StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& directi { } -const PickRay StaticRayPick::getPickRay(bool& valid) { +const PickRay StaticRayPick::getPickRay(bool& valid) const { valid = true; return _pickRay; } \ No newline at end of file diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index 6e2fe89e8c..05ff4ef397 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -18,7 +18,7 @@ class StaticRayPick : public RayPick { public: StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) override; + const PickRay getPickRay(bool& valid) const override; private: PickRay _pickRay; From 55a025b827ab5184e3d1311bf225f1004d0f25ee Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 18 Jul 2017 12:43:34 -0700 Subject: [PATCH 16/95] initial code review --- interface/src/Application.cpp | 12 ++++--- interface/src/raypick/JointRayPick.cpp | 3 +- interface/src/raypick/LaserPointer.cpp | 14 ++++---- interface/src/raypick/LaserPointer.h | 4 ++- interface/src/raypick/LaserPointerManager.cpp | 5 --- interface/src/raypick/LaserPointerManager.h | 6 ++-- .../LaserPointerScriptingInterface.cpp | 9 ++--- .../raypick/LaserPointerScriptingInterface.h | 17 +++++---- interface/src/raypick/RayPickManager.cpp | 13 ++----- interface/src/raypick/RayPickManager.h | 35 ++++++++++--------- 10 files changed, 55 insertions(+), 63 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44f15ff16e..69835caff0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -591,6 +591,10 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(); + return previousSessionCrashed; } @@ -4922,12 +4926,12 @@ void Application::update(float deltaTime) { { PROFILE_RANGE(app, "RayPick"); - RayPickManager::getInstance().update(); + DependencyManager::get()->update(); } { PROFILE_RANGE(app, "LaserPointerManager"); - LaserPointerManager::getInstance().update(); + DependencyManager::get()->update(); } // Update _viewFrustum with latest camera and view frustum data... @@ -5775,7 +5779,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AvatarBookmarks", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LocationBookmarks", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("LaserPointers", LaserPointerScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("LaserPointers", DependencyManager::get().data()); // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); @@ -5828,7 +5832,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); - scriptEngine->registerGlobalObject("RayPick", &RayPickManager::getInstance()); + scriptEngine->registerGlobalObject("RayPick", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index 3281d307d9..f6be58437f 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -24,7 +24,8 @@ JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const PickRay JointRayPick::getPickRay(bool& valid) const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(_jointName); - if (jointIndex != -1) { + const int INVALID_JOINT = -1; + if (jointIndex != INVALID_JOINT) { glm::vec3 jointPos = myAvatar->getAbsoluteJointTranslationInObjectFrame(jointIndex); glm::quat jointRot = myAvatar->getAbsoluteJointRotationInObjectFrame(jointIndex); glm::vec3 avatarPos = myAvatar->getPosition(); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index ed5fbd2ece..930e72a6fe 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -23,7 +23,7 @@ LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, _faceAvatar(faceAvatar), _centerEndY(centerEndY) { - _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); + _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); for (auto& state : _renderStates.keys()) { if (!enabled || state != _currentRenderState) { @@ -39,7 +39,7 @@ LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction _faceAvatar(faceAvatar), _centerEndY(centerEndY) { - _rayPickUID = RayPickManager::getInstance().addRayPick(std::make_shared(position, direction, filter, maxDistance, enabled)); + _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(position, direction, filter, maxDistance, enabled)); for (auto& state : _renderStates.keys()) { if (!enabled || state != _currentRenderState) { @@ -49,7 +49,7 @@ LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction } LaserPointer::~LaserPointer() { - RayPickManager::getInstance().removeRayPick(_rayPickUID); + DependencyManager::get()->removeRayPick(_rayPickUID); for (RenderState& renderState : _renderStates) { if (!renderState.getStartID().isNull()) { qApp->getOverlays().deleteOverlay(renderState.getStartID()); @@ -64,12 +64,12 @@ LaserPointer::~LaserPointer() { } void LaserPointer::enable() { - RayPickManager::getInstance().enableRayPick(_rayPickUID); + DependencyManager::get()->enableRayPick(_rayPickUID); _renderingEnabled = true; } void LaserPointer::disable() { - RayPickManager::getInstance().disableRayPick(_rayPickUID); + DependencyManager::get()->disableRayPick(_rayPickUID); _renderingEnabled = false; if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { disableRenderState(_currentRenderState); @@ -105,9 +105,9 @@ void LaserPointer::disableRenderState(const QString& renderState) { } void LaserPointer::update() { - RayPickResult prevRayPickResult = RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); + RayPickResult prevRayPickResult = DependencyManager::get()->getPrevRayPickResult(_rayPickUID); if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState) && prevRayPickResult.type != IntersectionType::NONE) { - PickRay pickRay = RayPickManager::getInstance().getPickRay(_rayPickUID); + PickRay pickRay = DependencyManager::get()->getPickRay(_rayPickUID); if (!_renderStates[_currentRenderState].getStartID().isNull()) { QVariantMap startProps; startProps.insert("position", vec3toVariant(pickRay.origin)); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 075ec5e7f7..ba9a876556 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -14,6 +14,8 @@ #include #include "glm/glm.hpp" #include "ui/overlays/Overlay.h" + +#include #include "RayPickManager.h" class RayPickResult; @@ -53,7 +55,7 @@ public: unsigned int getUID() { return _rayPickUID; } void enable(); void disable(); - const RayPickResult getPrevRayPickResult() { return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } + const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } void setRenderState(const QString& state); void disableRenderState(const QString& renderState); diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index e4c9e18127..b8086c2f89 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -12,11 +12,6 @@ #include "LaserPointer.h" #include "RayPick.h" -LaserPointerManager& LaserPointerManager::getInstance() { - static LaserPointerManager instance; - return instance; -} - unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index f5a8484054..fc043a9685 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -17,14 +17,14 @@ #include #include "LaserPointer.h" +#include "DependencyManager.h" class RayPickResult; -class LaserPointerManager { +class LaserPointerManager : public Dependency { + SINGLETON_DEPENDENCY public: - static LaserPointerManager& getInstance(); - unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); unsigned int createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index cf0289c44b..a53b3dbf01 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -17,11 +17,6 @@ #include "Application.h" -LaserPointerScriptingInterface* LaserPointerScriptingInterface::getInstance() { - static LaserPointerScriptingInterface instance; - return &instance; -} - uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { QVariantMap propertyMap = properties.toMap(); @@ -104,7 +99,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop dirOffset = vec3FromVariant(propertyMap["dirOffset"]); } - return LaserPointerManager::getInstance().createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + return DependencyManager::get()->createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); } else if (propertyMap["position"].isValid()) { glm::vec3 position = vec3FromVariant(propertyMap["position"]); @@ -113,7 +108,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop direction = vec3FromVariant(propertyMap["direction"]); } - return LaserPointerManager::getInstance().createLaserPointer(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + return DependencyManager::get()->createLaserPointer(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); } return 0; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index b16daedda6..708c378abb 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -15,20 +15,19 @@ #include "LaserPointerManager.h" #include "RegisteredMetaTypes.h" +#include "DependencyManager.h" -class LaserPointerScriptingInterface : public QObject { +class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT - -public: - static LaserPointerScriptingInterface* getInstance(); + SINGLETON_DEPENDENCY public slots: Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties); - Q_INVOKABLE void enableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().enableLaserPointer(uid); } - Q_INVOKABLE void disableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().disableLaserPointer(uid); } - Q_INVOKABLE void removeLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().removeLaserPointer(uid); } - Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) { LaserPointerManager::getInstance().setRenderState(uid, renderState); } - Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return LaserPointerManager::getInstance().getPrevRayPickResult(uid); } + Q_INVOKABLE void enableLaserPointer(unsigned int uid) { DependencyManager::get()->enableLaserPointer(uid); } + Q_INVOKABLE void disableLaserPointer(unsigned int uid) { DependencyManager::get()->disableLaserPointer(uid); } + Q_INVOKABLE void removeLaserPointer(unsigned int uid) { DependencyManager::get()->removeLaserPointer(uid); } + Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) { DependencyManager::get()->setRenderState(uid, renderState); } + Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return DependencyManager::get()->getPrevRayPickResult(uid); } }; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 8ca503114c..ff4fca3f50 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -19,13 +19,7 @@ #include "scripting/HMDScriptingInterface.h" #include "DependencyManager.h" -RayPickManager& RayPickManager::getInstance() { - static RayPickManager instance; - return instance; -} - -// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer -bool RayPickManager::checkAndCompareCachedResults(QPair& ray, QHash, QHash>& cache, RayPickResult& res, unsigned int mask) { +bool RayPickManager::checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, unsigned int mask) { if (cache.contains(ray) && cache[ray].contains(mask)) { if (cache[ray][mask].distance < res.distance) { res = cache[ray][mask]; @@ -35,8 +29,7 @@ bool RayPickManager::checkAndCompareCachedResults(QPair& r return false; } -void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, - QPair& ray, QHash, QHash>& cache) { +void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, QPair& ray, RayPickCache& cache) { if (intersects) { cache[ray][mask] = resTemp; if (resTemp.distance < res.distance) { @@ -48,7 +41,7 @@ void RayPickManager::cacheResult(const bool intersects, const RayPickResult& res } void RayPickManager::update() { - QHash, QHash> results; + RayPickCache results; for (auto& uid : _rayPicks.keys()) { std::shared_ptr rayPick = _rayPicks[uid]; if (!rayPick->isEnabled() || rayPick->getFilter() == RayPickMask::PICK_NOTHING || rayPick->getMaxDistance() < 0.0f) { diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index ad4fb3f286..7ecb028d29 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -11,33 +11,34 @@ #ifndef hifi_RayPickManager_h #define hifi_RayPickManager_h -#include "RegisteredMetaTypes.h" - #include #include #include #include #include +#include "RegisteredMetaTypes.h" +#include "DependencyManager.h" + class RayPick; class RayPickResult; enum RayPickMask { PICK_NOTHING = 0, - PICK_ENTITIES = 1, - PICK_OVERLAYS = 2, - PICK_AVATARS = 4, - PICK_HUD = 8, + PICK_ENTITIES = 1 << 0, + PICK_OVERLAYS = 1 << 1, + PICK_AVATARS = 1 << 2, + PICK_HUD = 1 << 3, - PICK_BOUNDING_BOX = 16, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) + PICK_BOUNDING_BOX = 1 << 4, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) - PICK_INCLUDE_INVISIBLE = 32, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements - PICK_INCLUDE_NONCOLLIDABLE = 64, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements + PICK_INCLUDE_INVISIBLE = 1 << 5, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements + PICK_INCLUDE_NONCOLLIDABLE = 1 << 6, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements - PICK_ALL_INTERSECTIONS = 128 // if not set, returns closest intersection, otherwise, returns list of all intersections + PICK_ALL_INTERSECTIONS = 1 << 7 // if not set, returns closest intersection, otherwise, returns list of all intersections }; -class RayPickManager : public QObject { +class RayPickManager : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) @@ -53,14 +54,10 @@ class RayPickManager : public QObject { Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) + SINGLETON_DEPENDENCY public: - static RayPickManager& getInstance(); - void update(); - bool checkAndCompareCachedResults(QPair& ray, QHash, QHash>& cache, RayPickResult& res, unsigned int mask); - void cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, - QPair& ray, QHash, QHash>& cache); unsigned int addRayPick(std::shared_ptr rayPick); void removeRayPick(const unsigned int uid); void enableRayPick(const unsigned int uid); @@ -78,6 +75,12 @@ private: QQueue _rayPicksToRemove; QReadWriteLock _containsLock; + typedef QHash, QHash> RayPickCache; + + // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer + bool checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, unsigned int mask); + void cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, QPair& ray, RayPickCache& cache); + unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } unsigned int PICK_OVERLAYS() { return RayPickMask::PICK_OVERLAYS; } From c6b3f69db0af9033d0aaad93bb871ef66c5c0792 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 19 Jul 2017 11:51:31 -0700 Subject: [PATCH 17/95] teleport third eye laser on invalid hand pose --- interface/src/raypick/JointRayPick.cpp | 11 +-- scripts/system/controllers/teleport.js | 99 ++++++++++++++++++++------ 2 files changed, 85 insertions(+), 25 deletions(-) diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index f6be58437f..6803700e4b 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -24,15 +24,16 @@ JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const PickRay JointRayPick::getPickRay(bool& valid) const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(_jointName); + bool useAvatarHead = _jointName == "Avatar"; const int INVALID_JOINT = -1; - if (jointIndex != INVALID_JOINT) { - glm::vec3 jointPos = myAvatar->getAbsoluteJointTranslationInObjectFrame(jointIndex); - glm::quat jointRot = myAvatar->getAbsoluteJointRotationInObjectFrame(jointIndex); + if (jointIndex != INVALID_JOINT || useAvatarHead) { + glm::vec3 jointPos = useAvatarHead ? myAvatar->getHeadPosition() : myAvatar->getAbsoluteJointTranslationInObjectFrame(jointIndex); + glm::quat jointRot = useAvatarHead ? myAvatar->getHeadOrientation() : myAvatar->getAbsoluteJointRotationInObjectFrame(jointIndex); glm::vec3 avatarPos = myAvatar->getPosition(); glm::quat avatarRot = myAvatar->getOrientation(); - glm::vec3 pos = avatarPos + (avatarRot * jointPos); - glm::quat rot = avatarRot * jointRot; + glm::vec3 pos = useAvatarHead ? jointPos : avatarPos + (avatarRot * jointPos); + glm::quat rot = useAvatarHead ? jointRot * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT) : avatarRot * jointRot; // Apply offset pos = pos + (rot * _posOffset); diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index b72828ea6b..eaeb7767ac 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -46,6 +46,15 @@ var COLORS_TELEPORT_CANCEL = { var TELEPORT_CANCEL_RANGE = 1; var COOL_IN_DURATION = 500; +var handInfo = { + right: { + controllerInput: Controller.Standard.RightHand + }, + left: { + controllerInput: Controller.Standard.LeftHand + } +}; + var cancelPath = { type: "line3d", color: COLORS_TELEPORT_CANCEL, @@ -172,6 +181,21 @@ function Teleporter() { renderStates: teleportRenderStates }); + this.teleportRayHeadVisible = LaserPointers.createLaserPointer({ + joint: "Avatar", + filter: RayPick.PICK_ENTITIES, + faceAvatar: true, + centerEndY: false, + renderStates: teleportRenderStates + }); + this.teleportRayHeadInvisible = LaserPointers.createLaserPointer({ + joint: "Avatar", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + centerEndY: false, + renderStates: teleportRenderStates + }); + this.updateConnected = null; this.activeHand = null; @@ -193,6 +217,8 @@ function Teleporter() { LaserPointers.removeLaserPointer(this.teleportRayLeftInvisible); LaserPointers.removeLaserPointer(this.teleportRayRightVisible); LaserPointers.removeLaserPointer(this.teleportRayRightInvisible); + LaserPointers.removeLaserPointer(this.teleportRayHeadVisible); + LaserPointers.removeLaserPointer(this.teleportRayHeadInvisible); if (this.updateConnected === true) { Script.update.disconnect(this, this.update); @@ -213,14 +239,6 @@ function Teleporter() { Script.clearTimeout(coolInTimeout); } - if (hand === 'right') { - LaserPointers.enableLaserPointer(_this.teleportRayRightVisible); - LaserPointers.enableLaserPointer(_this.teleportRayRightInvisible); - } else { - LaserPointers.enableLaserPointer(_this.teleportRayLeftVisible); - LaserPointers.enableLaserPointer(_this.teleportRayLeftInvisible); - } - this.state = TELEPORTER_STATES.COOL_IN; coolInTimeout = Script.setTimeout(function() { if (_this.state === TELEPORTER_STATES.COOL_IN) { @@ -244,6 +262,8 @@ function Teleporter() { LaserPointers.disableLaserPointer(this.teleportRayLeftInvisible); LaserPointers.disableLaserPointer(this.teleportRayRightVisible); LaserPointers.disableLaserPointer(this.teleportRayRightInvisible); + LaserPointers.disableLaserPointer(this.teleportRayHeadVisible); + LaserPointers.disableLaserPointer(this.teleportRayHeadInvisible); this.updateConnected = null; this.state = TELEPORTER_STATES.IDLE; @@ -255,6 +275,31 @@ function Teleporter() { return; } + // Get current hand pose information to see if the pose is valid + var pose = Controller.getPoseValue(handInfo[_this.activeHand].controllerInput); + var mode = pose.valid ? _this.activeHand : 'head'; + if (!pose.valid) { + if (mode === 'right') { + LaserPointers.disableLaserPointer(_this.teleportRayRightVisible); + LaserPointers.disableLaserPointer(_this.teleportRayRightInvisible); + } else { + LaserPointers.disableLaserPointer(_this.teleportRayLeftVisible); + LaserPointers.disableLaserPointer(_this.teleportRayLeftInvisible); + } + LaserPointers.enableLaserPointer(_this.teleportRayHeadVisible); + LaserPointers.enableLaserPointer(_this.teleportRayHeadInvisible); + } else { + if (mode === 'right') { + LaserPointers.enableLaserPointer(_this.teleportRayRightVisible); + LaserPointers.enableLaserPointer(_this.teleportRayRightInvisible); + } else { + LaserPointers.enableLaserPointer(_this.teleportRayLeftVisible); + LaserPointers.enableLaserPointer(_this.teleportRayLeftInvisible); + } + LaserPointers.disableLaserPointer(_this.teleportRayHeadVisible); + LaserPointers.disableLaserPointer(_this.teleportRayHeadInvisible); + } + // We do up to 2 ray picks to find a teleport location. // There are 2 types of teleport locations we are interested in: // 1. A visible floor. This can be any entity surface that points within some degree of "up" @@ -264,28 +309,39 @@ function Teleporter() { // We might hit an invisible entity that is not a seat, so we need to do a second pass. // * In the second pass we pick against visible entities only. // - var result = (_this.activeHand === 'right') ? LaserPointers.getPrevRayPickResult(_this.teleportRayRightInvisible) : - LaserPointers.getPrevRayPickResult(_this.teleportRayLeftInvisible); + var result; + if (mode === 'right') { + result = LaserPointers.getPrevRayPickResult(_this.teleportRayRightInvisible); + } else if (mode === 'left') { + result = LaserPointers.getPrevRayPickResult(_this.teleportRayLeftInvisible); + } else { + result = LaserPointers.getPrevRayPickResult(_this.teleportRayHeadInvisible); + } var teleportLocationType = getTeleportTargetType(result); if (teleportLocationType === TARGET.INVISIBLE) { - result = (_this.activeHand === 'right') ? LaserPointers.getPrevRayPickResult(_this.teleportRayRightVisible) : - LaserPointers.getPrevRayPickResult(_this.teleportRayLeftVisible); + if (mode === 'right') { + result = LaserPointers.getPrevRayPickResult(_this.teleportRayRightVisible); + } else if (mode === 'left') { + result = LaserPointers.getPrevRayPickResult(_this.teleportRayLeftVisible); + } else { + result = LaserPointers.getPrevRayPickResult(_this.teleportRayHeadVisible); + } teleportLocationType = getTeleportTargetType(result); } if (teleportLocationType === TARGET.NONE) { - this.setTeleportState(_this.activeHand, "", ""); + this.setTeleportState(mode, "", ""); } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { - this.setTeleportState(_this.activeHand, "", "cancel"); + this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.SURFACE) { if (this.state === TELEPORTER_STATES.COOL_IN) { - this.setTeleportState(_this.activeHand, "cancel", ""); + this.setTeleportState(mode, "cancel", ""); } else { - this.setTeleportState(_this.activeHand, "teleport", ""); + this.setTeleportState(mode, "teleport", ""); } } else if (teleportLocationType === TARGET.SEAT) { - this.setTeleportState(_this.activeHand, "", "seat"); + this.setTeleportState(mode, "", "seat"); } @@ -308,13 +364,16 @@ function Teleporter() { } }; - this.setTeleportState = function(hand, visibleState, invisibleState) { - if (hand === 'right') { + this.setTeleportState = function(mode, visibleState, invisibleState) { + if (mode === 'right') { LaserPointers.setRenderState(_this.teleportRayRightVisible, visibleState); LaserPointers.setRenderState(_this.teleportRayRightInvisible, invisibleState); - } else { + } else if (mode === 'left') { LaserPointers.setRenderState(_this.teleportRayLeftVisible, visibleState); LaserPointers.setRenderState(_this.teleportRayLeftInvisible, invisibleState); + } else { + LaserPointers.setRenderState(_this.teleportRayHeadVisible, visibleState); + LaserPointers.setRenderState(_this.teleportRayHeadInvisible, invisibleState); } }; } From 912b417dd4574c65ac142fb3d3540e56b06550ce Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 19 Jul 2017 13:56:18 -0700 Subject: [PATCH 18/95] mouse ray pick --- interface/src/raypick/LaserPointer.cpp | 16 ++++++++++ interface/src/raypick/LaserPointer.h | 2 ++ interface/src/raypick/LaserPointerManager.cpp | 7 ++++ interface/src/raypick/LaserPointerManager.h | 2 ++ .../LaserPointerScriptingInterface.cpp | 24 ++++++++------ interface/src/raypick/MouseRayPick.cpp | 32 +++++++++++++++++++ interface/src/raypick/MouseRayPick.h | 26 +++++++++++++++ 7 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 interface/src/raypick/MouseRayPick.cpp create mode 100644 interface/src/raypick/MouseRayPick.h diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 930e72a6fe..a4538e4aff 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -12,6 +12,7 @@ #include "JointRayPick.h" #include "StaticRayPick.h" +#include "MouseRayPick.h" #include "Application.h" #include "avatar/AvatarManager.h" @@ -48,6 +49,21 @@ LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction } } +LaserPointer::LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) : + _renderingEnabled(enabled), + _renderStates(renderStates), + _faceAvatar(faceAvatar), + _centerEndY(centerEndY) +{ + _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(filter, maxDistance, enabled)); + + for (auto& state : _renderStates.keys()) { + if (!enabled || state != _currentRenderState) { + disableRenderState(state); + } + } +} + LaserPointer::~LaserPointer() { DependencyManager::get()->removeRayPick(_rayPickUID); for (RenderState& renderState : _renderStates) { diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index ba9a876556..fef7fe62f1 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -50,6 +50,8 @@ public: const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); + LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, + const bool centerEndY, const bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index b8086c2f89..12f0223297 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -28,6 +28,13 @@ unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, return uid; } +unsigned int LaserPointerManager::createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + unsigned int uid = laserPointer->getUID(); + _laserPointers[uid] = laserPointer; + return uid; +} + void LaserPointerManager::enableLaserPointer(const unsigned int uid) { if (_laserPointers.contains(uid)) { _laserPointers[uid]->enable(); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index fc043a9685..6eb649efd4 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -29,6 +29,8 @@ public: const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); unsigned int createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); + unsigned int createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, + const bool centerEndY, const bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index a53b3dbf01..3260ffc165 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -88,18 +88,22 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop if (propertyMap["joint"].isValid()) { QString jointName = propertyMap["joint"].toString(); - // x = upward, y = forward, z = lateral - glm::vec3 posOffset = Vectors::ZERO; - if (propertyMap["posOffset"].isValid()) { - posOffset = vec3FromVariant(propertyMap["posOffset"]); - } + if (jointName != "Mouse") { + // x = upward, y = forward, z = lateral + glm::vec3 posOffset = Vectors::ZERO; + if (propertyMap["posOffset"].isValid()) { + posOffset = vec3FromVariant(propertyMap["posOffset"]); + } - glm::vec3 dirOffset = Vectors::UP; - if (propertyMap["dirOffset"].isValid()) { - dirOffset = vec3FromVariant(propertyMap["dirOffset"]); - } + glm::vec3 dirOffset = Vectors::UP; + if (propertyMap["dirOffset"].isValid()) { + dirOffset = vec3FromVariant(propertyMap["dirOffset"]); + } - return DependencyManager::get()->createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + return DependencyManager::get()->createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + } else { + return DependencyManager::get()->createLaserPointer(filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + } } else if (propertyMap["position"].isValid()) { glm::vec3 position = vec3FromVariant(propertyMap["position"]); diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp new file mode 100644 index 0000000000..39dcb74090 --- /dev/null +++ b/interface/src/raypick/MouseRayPick.cpp @@ -0,0 +1,32 @@ +// +// MouseRayPick.cpp +// interface/src/raypick +// +// Created by Sam Gondelman 7/19/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "MouseRayPick.h" + +#include "DependencyManager.h" +#include "Application.h" +#include "display-plugins/CompositorHelper.h" + +MouseRayPick::MouseRayPick(const uint16_t filter, const float maxDistance, const bool enabled) : + RayPick(filter, maxDistance, enabled) +{ +} + +const PickRay MouseRayPick::getPickRay(bool& valid) const { + QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition(); + if (position.isValid()) { + QVariantMap posMap = position.toMap(); + valid = true; + return qApp->getCamera().computePickRay(posMap["x"].toFloat(), posMap["y"].toFloat()); + } + + valid = false; + return PickRay(); +} diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h new file mode 100644 index 0000000000..473d1871e8 --- /dev/null +++ b/interface/src/raypick/MouseRayPick.h @@ -0,0 +1,26 @@ +// +// MouseRayPick.h +// interface/src/raypick +// +// Created by Sam Gondelman 7/19/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_MouseRayPick_h +#define hifi_MouseRayPick_h + +#include "RayPick.h" + +#include + +class MouseRayPick : public RayPick { + +public: + MouseRayPick(const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + + const PickRay getPickRay(bool& valid) const override; +}; + +#endif // hifi_MouseRayPick_h From bf243d60255c8ce940ae86ef9f59e8bba7493bc7 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 19 Jul 2017 17:45:21 -0700 Subject: [PATCH 19/95] lockEnd, editRenderState, and updated grab.js --- interface/src/raypick/LaserPointer.cpp | 50 ++++++-- interface/src/raypick/LaserPointer.h | 15 ++- interface/src/raypick/LaserPointerManager.cpp | 19 ++- interface/src/raypick/LaserPointerManager.h | 7 +- .../LaserPointerScriptingInterface.cpp | 89 ++++++++----- .../raypick/LaserPointerScriptingInterface.h | 4 + scripts/system/controllers/grab.js | 119 +++++++++--------- 7 files changed, 191 insertions(+), 112 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index a4538e4aff..057901bdb6 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -18,11 +18,12 @@ #include "avatar/AvatarManager.h" LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) : + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _faceAvatar(faceAvatar), - _centerEndY(centerEndY) + _centerEndY(centerEndY), + _lockEnd(lockEnd) { _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); @@ -34,11 +35,12 @@ LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, } LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) : + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _faceAvatar(faceAvatar), - _centerEndY(centerEndY) + _centerEndY(centerEndY), + _lockEnd(lockEnd) { _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(position, direction, filter, maxDistance, enabled)); @@ -49,11 +51,13 @@ LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction } } -LaserPointer::LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) : +LaserPointer::LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, + const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _faceAvatar(faceAvatar), - _centerEndY(centerEndY) + _centerEndY(centerEndY), + _lockEnd(lockEnd) { _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(filter, maxDistance, enabled)); @@ -99,6 +103,27 @@ void LaserPointer::setRenderState(const QString& state) { _currentRenderState = state; } +void LaserPointer::editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { + _renderStates[state].setStartID(updateRenderStateOverlay(_renderStates[state].getStartID(), startProps)); + _renderStates[state].setPathID(updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps)); + _renderStates[state].setEndID(updateRenderStateOverlay(_renderStates[state].getEndID(), endProps)); +} + +OverlayID LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& props) { + if (props.isValid()) { + if (!id.isNull()) { + qApp->getOverlays().editOverlay(id, props); + return id; + } else { + QVariantMap propsMap = props.toMap(); + if (propsMap["type"].isValid()) { + return qApp->getOverlays().addOverlay(propsMap["type"].toString(), props); + } + } + } + return OverlayID(); +} + void LaserPointer::disableRenderState(const QString& renderState) { if (!_renderStates[renderState].getStartID().isNull()) { QVariantMap startProps; @@ -131,7 +156,18 @@ void LaserPointer::update() { startProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesStartIgnoreRays()); qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getStartID(), startProps); } - glm::vec3 endVec = pickRay.origin + pickRay.direction * prevRayPickResult.distance; + glm::vec3 endVec; + if (!_lockEnd || prevRayPickResult.type == IntersectionType::HUD) { + endVec = pickRay.origin + pickRay.direction * prevRayPickResult.distance; + } else { + if (prevRayPickResult.type == IntersectionType::ENTITY) { + endVec = DependencyManager::get()->getEntityTransform(prevRayPickResult.objectID)[3]; + } else if (prevRayPickResult.type == IntersectionType::OVERLAY) { + endVec = vec3FromVariant(qApp->getOverlays().getProperty(prevRayPickResult.objectID, "position").value); + } else if (prevRayPickResult.type == IntersectionType::AVATAR) { + endVec = DependencyManager::get()->getAvatar(prevRayPickResult.objectID)->getPosition(); + } + } QVariant end = vec3toVariant(endVec); if (!_renderStates[_currentRenderState].getPathID().isNull()) { QVariantMap pathProps; diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index fef7fe62f1..de302ca6dc 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -29,6 +29,9 @@ public: const OverlayID& getStartID() { return _startID; } const OverlayID& getPathID() { return _pathID; } const OverlayID& getEndID() { return _endID; } + void setStartID(const OverlayID& startID) { _startID = startID; } + void setPathID(const OverlayID& pathID) { _pathID = pathID; } + void setEndID(const OverlayID& endID) { _endID = endID; } const bool& doesStartIgnoreRays() { return _startIgnoreRays; } const bool& doesPathIgnoreRays() { return _pathIgnoreRays; } const bool& doesEndIgnoreRays() { return _endIgnoreRays; } @@ -47,11 +50,11 @@ class LaserPointer { public: LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, - const bool centerEndY, const bool enabled); + const bool centerEndY, const bool lockEnd, const bool enabled); ~LaserPointer(); unsigned int getUID() { return _rayPickUID; } @@ -60,7 +63,7 @@ public: const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } void setRenderState(const QString& state); - void disableRenderState(const QString& renderState); + void editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); void update(); @@ -70,8 +73,12 @@ private: QHash _renderStates; bool _faceAvatar; bool _centerEndY; + bool _lockEnd; unsigned int _rayPickUID; + + OverlayID updateRenderStateOverlay(const OverlayID& id, const QVariant& props); + void disableRenderState(const QString& renderState); }; #endif // hifi_LaserPointer_h diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 12f0223297..f60d9639ac 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -13,23 +13,24 @@ #include "RayPick.h" unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; } unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; } -unsigned int LaserPointerManager::createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); +unsigned int LaserPointerManager::createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, + const bool centerEndY, const bool lockEnd, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); unsigned int uid = laserPointer->getUID(); _laserPointers[uid] = laserPointer; return uid; @@ -53,6 +54,12 @@ void LaserPointerManager::setRenderState(unsigned int uid, const QString & rende } } +void LaserPointerManager::editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { + if (_laserPointers.contains(uid)) { + _laserPointers[uid]->editRenderState(state, startProps, pathProps, endProps); + } +} + const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { if (_laserPointers.contains(uid)) { return _laserPointers[uid]->getPrevRayPickResult(); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 6eb649efd4..574a4d9e96 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -26,15 +26,16 @@ class LaserPointerManager : public Dependency { public: unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); unsigned int createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool enabled); + const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); unsigned int createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, - const bool centerEndY, const bool enabled); + const bool centerEndY, const bool lockEnd, const bool enabled); void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); void setRenderState(unsigned int uid, const QString& renderState); + void editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); const RayPickResult getPrevRayPickResult(const unsigned int uid); void update(); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 3260ffc165..1cc3a967c4 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -40,6 +40,11 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop centerEndY = propertyMap["centerEndY"].toBool(); } + bool lockEnd = false; + if (propertyMap["lockEnd"].isValid()) { + lockEnd = propertyMap["lockEnd"].toBool(); + } + bool enabled = false; if (propertyMap["enabled"].isValid()) { enabled = propertyMap["enabled"].toBool(); @@ -53,33 +58,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop QVariantMap renderStateMap = renderStateVariant.toMap(); if (renderStateMap["name"].isValid()) { QString name = renderStateMap["name"].toString(); - - QUuid startID; - if (renderStateMap["start"].isValid()) { - QVariantMap startMap = renderStateMap["start"].toMap(); - if (startMap["type"].isValid()) { - startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); - } - } - - QUuid pathID; - if (renderStateMap["path"].isValid()) { - QVariantMap pathMap = renderStateMap["path"].toMap(); - // right now paths must be line3ds - if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { - pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); - } - } - - QUuid endID; - if (renderStateMap["end"].isValid()) { - QVariantMap endMap = renderStateMap["end"].toMap(); - if (endMap["type"].isValid()) { - endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); - } - } - - renderStates[name] = RenderState(startID, pathID, endID); + renderStates[name] = buildRenderState(renderStateMap); } } } @@ -100,9 +79,9 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop dirOffset = vec3FromVariant(propertyMap["dirOffset"]); } - return DependencyManager::get()->createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + return DependencyManager::get()->createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); } else { - return DependencyManager::get()->createLaserPointer(filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + return DependencyManager::get()->createLaserPointer(filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); } } else if (propertyMap["position"].isValid()) { glm::vec3 position = vec3FromVariant(propertyMap["position"]); @@ -112,8 +91,58 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop direction = vec3FromVariant(propertyMap["direction"]); } - return DependencyManager::get()->createLaserPointer(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, enabled); + return DependencyManager::get()->createLaserPointer(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); } return 0; +} + +void LaserPointerScriptingInterface::editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) { + QVariantMap propMap = properties.toMap(); + + QVariant startProps; + if (propMap["start"].isValid()) { + startProps = propMap["start"]; + } + + QVariant pathProps; + if (propMap["path"].isValid()) { + pathProps = propMap["path"]; + } + + QVariant endProps; + if (propMap["end"].isValid()) { + endProps = propMap["end"]; + } + + DependencyManager::get()->editRenderState(uid, renderState, startProps, pathProps, endProps); +} + +const RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { + QUuid startID; + if (propMap["start"].isValid()) { + QVariantMap startMap = propMap["start"].toMap(); + if (startMap["type"].isValid()) { + startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); + } + } + + QUuid pathID; + if (propMap["path"].isValid()) { + QVariantMap pathMap = propMap["path"].toMap(); + // right now paths must be line3ds + if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { + pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); + } + } + + QUuid endID; + if (propMap["end"].isValid()) { + QVariantMap endMap = propMap["end"].toMap(); + if (endMap["type"].isValid()) { + endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); + } + } + + return RenderState(startID, pathID, endID); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 708c378abb..f91fa617ae 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -26,9 +26,13 @@ public slots: Q_INVOKABLE void enableLaserPointer(unsigned int uid) { DependencyManager::get()->enableLaserPointer(uid); } Q_INVOKABLE void disableLaserPointer(unsigned int uid) { DependencyManager::get()->disableLaserPointer(uid); } Q_INVOKABLE void removeLaserPointer(unsigned int uid) { DependencyManager::get()->removeLaserPointer(uid); } + Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties); Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) { DependencyManager::get()->setRenderState(uid, renderState); } Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return DependencyManager::get()->getPrevRayPickResult(uid); } +private: + const RenderState buildRenderState(const QVariantMap & propMap); + }; #endif // hifi_LaserPointerScriptingInterface_h diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index da8add5117..ae1474f140 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -197,53 +197,24 @@ Mouse.prototype.restoreRotateCursor = function() { var mouse = new Mouse(); - -// Beacon class stores info for drawing a line at object's target position -function Beacon() { - this.height = 0.10; - this.overlayID = Overlays.addOverlay("line3d", { - color: { - red: 200, - green: 200, - blue: 200 - }, - alpha: 1, - visible: false, - lineWidth: 2 - }); -} - -Beacon.prototype.enable = function() { - Overlays.editOverlay(this.overlayID, { - visible: true - }); +var beacon = { + type: "cube", + dimensions: { + x: 0.01, + y: 0, + z: 0.01 + }, + color: { + red: 200, + green: 200, + blue: 200 + }, + alpha: 1, + solid: true, + ignoreRayIntersection: true, + visible: true }; -Beacon.prototype.disable = function() { - Overlays.editOverlay(this.overlayID, { - visible: false - }); -}; - -Beacon.prototype.updatePosition = function(position) { - Overlays.editOverlay(this.overlayID, { - visible: true, - start: { - x: position.x, - y: position.y + this.height, - z: position.z - }, - end: { - x: position.x, - y: position.y - this.height, - z: position.z - } - }); -}; - -var beacon = new Beacon(); - - // TODO: play sounds again when we aren't leaking AudioInjector threads // var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav"); // var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav"); @@ -285,6 +256,19 @@ function Grabber() { this.liftKey = false; // SHIFT this.rotateKey = false; // CONTROL + + this.mouseRayOverlays = LaserPointers.createLaserPointer({ + joint: "Mouse", + filter: RayPick.PICK_OVERLAYS, + enabled: true + }); + this.mouseRayEntities = LaserPointers.createLaserPointer({ + joint: "Mouse", + filter: RayPick.PICK_ENTITIES, + lockEnd: true, + faceAvatar: true, + enabled: true + }); } Grabber.prototype.computeNewGrabPlane = function() { @@ -333,40 +317,43 @@ Grabber.prototype.pressEvent = function(event) { return; } - var pickRay = Camera.computePickRay(event.x, event.y); + var overlayResult = LaserPointers.getPrevRayPickResult(this.mouseRayOverlays); + if (overlayResult.type != RayPick.INTERSECTED_NONE) { + if (overlayResult.objectID == HMD.tabletID || overlayResult.objectID == HMD.tabletScreenID || overlayResult.objectID == HMD.homeButtonID) { + return; + } + } - var overlayResult = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); - if (overlayResult.intersects) { + var pickResults = LaserPointers.getPrevRayPickResult(this.mouseRayEntities); + if (pickResults.type == RayPick.INTERSECTED_NONE) { + LaserPointers.setRenderState(this.mouseRayEntities, ""); return; } - var pickResults = Entities.findRayIntersection(pickRay, true); // accurate picking - if (!pickResults.intersects) { - // didn't click on anything - return; - } - - var isDynamic = Entities.getEntityProperties(pickResults.entityID, "dynamic").dynamic; + var isDynamic = Entities.getEntityProperties(pickResults.objectID, "dynamic").dynamic; if (!isDynamic) { // only grab dynamic objects return; } - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, pickResults.entityID, DEFAULT_GRABBABLE_DATA); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, pickResults.objectID, DEFAULT_GRABBABLE_DATA); if (grabbableData.grabbable === false) { return; } + LaserPointers.setRenderState(this.mouseRayEntities, "grabbed"); + mouse.startDrag(event); - var clickedEntity = pickResults.entityID; + var clickedEntity = pickResults.objectID; var entityProperties = Entities.getEntityProperties(clickedEntity); this.startPosition = entityProperties.position; this.lastRotation = entityProperties.rotation; var cameraPosition = Camera.getPosition(); var objectBoundingDiameter = Vec3.length(entityProperties.dimensions); - beacon.height = objectBoundingDiameter; + beacon.dimensions.y = objectBoundingDiameter; + LaserPointers.editRenderState(this.mouseRayEntities, "grabbed", {end: beacon}); this.maxDistance = objectBoundingDiameter / MAX_SOLID_ANGLE; if (Vec3.distance(this.startPosition, cameraPosition) > this.maxDistance) { // don't allow grabs of things far away @@ -385,6 +372,7 @@ Grabber.prototype.pressEvent = function(event) { }; // compute the grab point + var pickRay = Camera.computePickRay(event.x, event.y); var nearestPoint = Vec3.subtract(this.startPosition, cameraPosition); var distanceToGrab = Vec3.dot(nearestPoint, pickRay.direction); nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction); @@ -395,8 +383,6 @@ Grabber.prototype.pressEvent = function(event) { this.computeNewGrabPlane(); - beacon.updatePosition(this.startPosition); - if (!entityIsGrabbedByOther(this.entityID)) { this.moveEvent(event); } @@ -431,7 +417,7 @@ Grabber.prototype.releaseEvent = function(event) { } this.actionID = null; - beacon.disable(); + LaserPointers.setRenderState(this.mouseRayEntities, ""); var args = "mouse"; Entities.callEntityMethod(this.entityID, "releaseGrab", args); @@ -552,7 +538,6 @@ Grabber.prototype.moveEventProcess = function() { ttl: ACTION_TTL }; - beacon.updatePosition(this.targetPosition); } if (!this.actionID) { @@ -586,6 +571,11 @@ Grabber.prototype.keyPressEvent = function(event) { this.computeNewGrabPlane(); }; +Grabber.prototype.cleanup = function() { + LaserPointers.removeLaserPointer(this.mouseRayEntities); + LaserPointers.removeLaserPointer(this.mouseRayOverlays); +}; + var grabber = new Grabber(); function pressEvent(event) { @@ -608,10 +598,15 @@ function keyReleaseEvent(event) { grabber.keyReleaseEvent(event); } +function cleanup() { + grabber.cleanup(); +} + Controller.mousePressEvent.connect(pressEvent); Controller.mouseMoveEvent.connect(moveEvent); Controller.mouseReleaseEvent.connect(releaseEvent); Controller.keyPressEvent.connect(keyPressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent); +Script.scriptEnding.connect(cleanup); }()); // END LOCAL_SCOPE From d156680bc8c00ef78bc53adf662ddc706ff75ade Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 20 Jul 2017 12:15:06 -0700 Subject: [PATCH 20/95] ignore/include by ID, simplified caching logic --- interface/src/raypick/LaserPointer.h | 7 ++ interface/src/raypick/LaserPointerManager.cpp | 77 ++++++++++++- interface/src/raypick/LaserPointerManager.h | 11 +- .../raypick/LaserPointerScriptingInterface.h | 7 ++ interface/src/raypick/MouseRayPick.h | 2 - interface/src/raypick/RayPick.h | 19 +++ interface/src/raypick/RayPickManager.cpp | 108 ++++++++++-------- interface/src/raypick/RayPickManager.h | 7 ++ scripts/system/controllers/grab.js | 5 +- 9 files changed, 190 insertions(+), 53 deletions(-) diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index de302ca6dc..ec96dfd76f 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -65,6 +65,13 @@ public: void setRenderState(const QString& state); void editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); + void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(_rayPickUID, ignoreEntities); } + void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(_rayPickUID, includeEntities); } + void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); } + void setIncludeOverlays(const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(_rayPickUID, includeOverlays); } + void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(_rayPickUID, ignoreAvatars); } + void setIncludeAvatars(const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(_rayPickUID, includeAvatars); } + void update(); private: diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index f60d9639ac..5235c7736a 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -16,7 +16,9 @@ unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, c const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); unsigned int uid = laserPointer->getUID(); + QWriteLocker lock(&_lock); _laserPointers[uid] = laserPointer; + _laserPointerLocks[uid] = std::make_shared(); return uid; } @@ -24,7 +26,9 @@ unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); unsigned int uid = laserPointer->getUID(); + QWriteLocker lock(&_lock); _laserPointers[uid] = laserPointer; + _laserPointerLocks[uid] = std::make_shared(); return uid; } @@ -32,43 +36,112 @@ unsigned int LaserPointerManager::createLaserPointer(const uint16_t filter, cons const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); unsigned int uid = laserPointer->getUID(); + QWriteLocker lock(&_lock); _laserPointers[uid] = laserPointer; + _laserPointerLocks[uid] = std::make_shared(); return uid; } +void LaserPointerManager::removeLaserPointer(const unsigned int uid) { + QWriteLocker lock(&_lock); + _laserPointers.remove(uid); + _laserPointerLocks.remove(uid); +} + void LaserPointerManager::enableLaserPointer(const unsigned int uid) { + QReadLocker lock(&_lock); if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->enable(); } } void LaserPointerManager::disableLaserPointer(const unsigned int uid) { + QReadLocker lock(&_lock); if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->disable(); } } void LaserPointerManager::setRenderState(unsigned int uid, const QString & renderState) { + QReadLocker lock(&_lock); if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setRenderState(renderState); } } void LaserPointerManager::editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { + QReadLocker lock(&_lock); if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->editRenderState(state, startProps, pathProps, endProps); } } const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { + QReadLocker lock(&_lock); if (_laserPointers.contains(uid)) { + QReadLocker laserLock(_laserPointerLocks[uid].get()); return _laserPointers[uid]->getPrevRayPickResult(); } return RayPickResult(); } void LaserPointerManager::update() { - for (auto& laserPointer : _laserPointers) { - laserPointer->update(); + QReadLocker lock(&_lock); + for (unsigned int uid : _laserPointers.keys()) { + // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts + QReadLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->update(); + } +} + +void LaserPointerManager::setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { + QReadLocker lock(&_lock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setIgnoreEntities(ignoreEntities); + } +} + +void LaserPointerManager::setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { + QReadLocker lock(&_lock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setIncludeEntities(includeEntities); + } +} + +void LaserPointerManager::setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { + QReadLocker lock(&_lock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setIgnoreOverlays(ignoreOverlays); + } +} + +void LaserPointerManager::setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { + QReadLocker lock(&_lock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setIncludeOverlays(includeOverlays); + } +} + +void LaserPointerManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { + QReadLocker lock(&_lock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setIgnoreAvatars(ignoreAvatars); + } +} + +void LaserPointerManager::setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { + QReadLocker lock(&_lock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setIncludeAvatars(includeAvatars); } } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 574a4d9e96..a550de694a 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -31,17 +31,26 @@ public: const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); unsigned int createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } + void removeLaserPointer(const unsigned int uid); void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); void setRenderState(unsigned int uid, const QString& renderState); void editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); const RayPickResult getPrevRayPickResult(const unsigned int uid); + void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities); + void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities); + void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays); + void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays); + void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars); + void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars); + void update(); private: QHash> _laserPointers; + QReadWriteLock _lock; + QHash> _laserPointerLocks; }; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index f91fa617ae..d4297c59ac 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -30,6 +30,13 @@ public slots: Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) { DependencyManager::get()->setRenderState(uid, renderState); } Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return DependencyManager::get()->getPrevRayPickResult(uid); } + Q_INVOKABLE void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(uid, ignoreEntities); } + Q_INVOKABLE void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(uid, includeEntities); } + Q_INVOKABLE void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(uid, ignoreOverlays); } + Q_INVOKABLE void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(uid, includeOverlays); } + Q_INVOKABLE void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(uid, ignoreAvatars); } + Q_INVOKABLE void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(uid, includeAvatars); } + private: const RenderState buildRenderState(const QVariantMap & propMap); diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index 473d1871e8..84d1c86e24 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -13,8 +13,6 @@ #include "RayPick.h" -#include - class MouseRayPick : public RayPick { public: diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index e149611210..ca9660729a 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -31,12 +31,31 @@ public: void setRayPickResult(const RayPickResult& rayPickResult) { _prevResult = rayPickResult; } + const QScriptValue& getIgnoreEntites() { return _ignoreEntities; } + const QScriptValue& getIncludeEntites() { return _includeEntities; } + const QScriptValue& getIgnoreOverlays() { return _ignoreOverlays; } + const QScriptValue& getIncludeOverlays() { return _includeOverlays; } + const QScriptValue& getIgnoreAvatars() { return _ignoreAvatars; } + const QScriptValue& getIncludeAvatars() { return _includeAvatars; } + void setIgnoreEntities(const QScriptValue& ignoreEntities) { _ignoreEntities = ignoreEntities; } + void setIncludeEntities(const QScriptValue& includeEntities) { _includeEntities = includeEntities; } + void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { _ignoreOverlays = ignoreOverlays; } + void setIncludeOverlays(const QScriptValue& includeOverlays) { _includeOverlays = includeOverlays; } + void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { _ignoreAvatars = ignoreAvatars; } + void setIncludeAvatars(const QScriptValue& includeAvatars) { _includeAvatars = includeAvatars; } + private: uint16_t _filter; float _maxDistance; bool _enabled; RayPickResult _prevResult; + QScriptValue _ignoreEntities; + QScriptValue _includeEntities; + QScriptValue _ignoreOverlays; + QScriptValue _includeOverlays; + QScriptValue _ignoreAvatars; + QScriptValue _includeAvatars; }; #endif // hifi_RayPick_h diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index ff4fca3f50..b7952bfef3 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -63,70 +63,40 @@ void RayPickManager::update() { if (rayPick->getFilter() & RayPickMask::PICK_ENTITIES) { RayToEntityIntersectionResult entityRes; bool fromCache = true; - if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { - entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); - fromCache = false; - } - } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { - entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); - fromCache = false; - } - } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { - entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); - fromCache = false; - } - } else { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES)) { - entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); - fromCache = false; - } + unsigned int invisible = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE; + unsigned int noncollidable = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; + unsigned int entityMask = RayPickMask::PICK_ENTITIES | invisible | noncollidable; + if (!checkAndCompareCachedResults(rayKey, results, res, entityMask)) { + entityRes = DependencyManager::get()->findRayIntersection(ray, true, rayPick->getIncludeEntites(), rayPick->getIgnoreEntites(), !invisible, !noncollidable); + fromCache = false; } if (!fromCache) { - unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal), - RayPickMask::PICK_ENTITIES | mask, res, rayKey, results); + entityMask, res, rayKey, results); } } if (rayPick->getFilter() & RayPickMask::PICK_OVERLAYS) { RayToOverlayIntersectionResult overlayRes; bool fromCache = true; - if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { - overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); - fromCache = false; - } - } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { - overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); - fromCache = false; - } - } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { - overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); - fromCache = false; - } - } else { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { - overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); - fromCache = false; - } + unsigned int invisible = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE; + unsigned int noncollidable = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; + unsigned int overlayMask = RayPickMask::PICK_OVERLAYS | invisible | noncollidable; + if (!checkAndCompareCachedResults(rayKey, results, res, overlayMask)) { + overlayRes = qApp->getOverlays().findRayIntersection(ray, true, rayPick->getIncludeOverlays(), rayPick->getIgnoreOverlays(), !invisible, !noncollidable); + fromCache = false; } if (!fromCache) { - unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal), - RayPickMask::PICK_OVERLAYS | mask, res, rayKey, results); + overlayMask, res, rayKey, results); } } if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_AVATARS)) { - RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, QScriptValue(), QScriptValue()); + RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars()); cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), RayPickMask::PICK_AVATARS, res, rayKey, results); } } @@ -214,3 +184,51 @@ const RayPickResult RayPickManager::getPrevRayPickResult(const unsigned int uid) } return RayPickResult(); } + +void RayPickManager::setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { + QReadLocker containsLock(&_containsLock); + if (_rayPicks.contains(uid)) { + QWriteLocker lock(_rayPickLocks[uid].get()); + _rayPicks[uid]->setIgnoreEntities(ignoreEntities); + } +} + +void RayPickManager::setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { + QReadLocker containsLock(&_containsLock); + if (_rayPicks.contains(uid)) { + QWriteLocker lock(_rayPickLocks[uid].get()); + _rayPicks[uid]->setIncludeEntities(includeEntities); + } +} + +void RayPickManager::setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { + QReadLocker containsLock(&_containsLock); + if (_rayPicks.contains(uid)) { + QWriteLocker lock(_rayPickLocks[uid].get()); + _rayPicks[uid]->setIgnoreOverlays(ignoreOverlays); + } +} + +void RayPickManager::setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { + QReadLocker containsLock(&_containsLock); + if (_rayPicks.contains(uid)) { + QWriteLocker lock(_rayPickLocks[uid].get()); + _rayPicks[uid]->setIncludeOverlays(includeOverlays); + } +} + +void RayPickManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { + QReadLocker containsLock(&_containsLock); + if (_rayPicks.contains(uid)) { + QWriteLocker lock(_rayPickLocks[uid].get()); + _rayPicks[uid]->setIgnoreAvatars(ignoreAvatars); + } +} + +void RayPickManager::setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { + QReadLocker containsLock(&_containsLock); + if (_rayPicks.contains(uid)) { + QWriteLocker lock(_rayPickLocks[uid].get()); + _rayPicks[uid]->setIncludeAvatars(includeAvatars); + } +} \ No newline at end of file diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 7ecb028d29..400098587e 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -65,6 +65,13 @@ public: const PickRay getPickRay(const unsigned int uid); const RayPickResult getPrevRayPickResult(const unsigned int uid); + void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities); + void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities); + void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays); + void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays); + void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars); + void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars); + private: QHash> _rayPicks; QHash> _rayPickLocks; diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index ae1474f140..411d5f6e41 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -262,6 +262,7 @@ function Grabber() { filter: RayPick.PICK_OVERLAYS, enabled: true }); + LaserPointers.setIncludeOverlays(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); this.mouseRayEntities = LaserPointers.createLaserPointer({ joint: "Mouse", filter: RayPick.PICK_ENTITIES, @@ -319,9 +320,7 @@ Grabber.prototype.pressEvent = function(event) { var overlayResult = LaserPointers.getPrevRayPickResult(this.mouseRayOverlays); if (overlayResult.type != RayPick.INTERSECTED_NONE) { - if (overlayResult.objectID == HMD.tabletID || overlayResult.objectID == HMD.tabletScreenID || overlayResult.objectID == HMD.homeButtonID) { - return; - } + return; } var pickResults = LaserPointers.getPrevRayPickResult(this.mouseRayEntities); From c7f0f03fcebdc30782d04559787004f5996f197c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 20 Jul 2017 13:53:39 -0700 Subject: [PATCH 21/95] expanded RayPick JS API --- interface/src/raypick/LaserPointer.cpp | 43 +--------- interface/src/raypick/LaserPointer.h | 10 +-- interface/src/raypick/LaserPointerManager.cpp | 84 +++++++++---------- interface/src/raypick/LaserPointerManager.h | 15 ++-- .../LaserPointerScriptingInterface.cpp | 42 +--------- interface/src/raypick/RayPickManager.cpp | 61 +++++++++++++- interface/src/raypick/RayPickManager.h | 24 +++--- scripts/system/controllers/grab.js | 8 +- 8 files changed, 129 insertions(+), 158 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 057901bdb6..76ed632027 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -10,56 +10,17 @@ // #include "LaserPointer.h" -#include "JointRayPick.h" -#include "StaticRayPick.h" -#include "MouseRayPick.h" - #include "Application.h" #include "avatar/AvatarManager.h" -LaserPointer::LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : +LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _faceAvatar(faceAvatar), _centerEndY(centerEndY), _lockEnd(lockEnd) { - _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); - - for (auto& state : _renderStates.keys()) { - if (!enabled || state != _currentRenderState) { - disableRenderState(state); - } - } -} - -LaserPointer::LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : - _renderingEnabled(enabled), - _renderStates(renderStates), - _faceAvatar(faceAvatar), - _centerEndY(centerEndY), - _lockEnd(lockEnd) -{ - _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(position, direction, filter, maxDistance, enabled)); - - for (auto& state : _renderStates.keys()) { - if (!enabled || state != _currentRenderState) { - disableRenderState(state); - } - } -} - -LaserPointer::LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, - const bool lockEnd, const bool enabled) : - _renderingEnabled(enabled), - _renderStates(renderStates), - _faceAvatar(faceAvatar), - _centerEndY(centerEndY), - _lockEnd(lockEnd) -{ - _rayPickUID = DependencyManager::get()->addRayPick(std::make_shared(filter, maxDistance, enabled)); + _rayPickUID = DependencyManager::get()->createRayPick(rayProps); for (auto& state : _renderStates.keys()) { if (!enabled || state != _currentRenderState) { diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index ec96dfd76f..909e61e00c 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -49,15 +49,11 @@ private: class LaserPointer { public: - LaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - LaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - LaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, - const bool centerEndY, const bool lockEnd, const bool enabled); + LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, + const bool lockEnd, const bool enabled); ~LaserPointer(); - unsigned int getUID() { return _rayPickUID; } + unsigned int getRayUID() { return _rayPickUID; } void enable(); void disable(); const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 5235c7736a..d9f3023263 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -12,44 +12,24 @@ #include "LaserPointer.h" #include "RayPick.h" -unsigned int LaserPointerManager::createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); - unsigned int uid = laserPointer->getUID(); - QWriteLocker lock(&_lock); - _laserPointers[uid] = laserPointer; - _laserPointerLocks[uid] = std::make_shared(); - return uid; -} - -unsigned int LaserPointerManager::createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); - unsigned int uid = laserPointer->getUID(); - QWriteLocker lock(&_lock); - _laserPointers[uid] = laserPointer; - _laserPointerLocks[uid] = std::make_shared(); - return uid; -} - -unsigned int LaserPointerManager::createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, - const bool centerEndY, const bool lockEnd, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); - unsigned int uid = laserPointer->getUID(); - QWriteLocker lock(&_lock); - _laserPointers[uid] = laserPointer; - _laserPointerLocks[uid] = std::make_shared(); - return uid; +unsigned int LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, + const bool lockEnd, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, faceAvatar, centerEndY, lockEnd, enabled); + if (laserPointer->getRayUID() != 0) { + QWriteLocker lock(&_addLock); + _laserPointersToAdd.enqueue(QPair>(_nextUID, laserPointer)); + return _nextUID++; + } + return 0; } void LaserPointerManager::removeLaserPointer(const unsigned int uid) { - QWriteLocker lock(&_lock); - _laserPointers.remove(uid); - _laserPointerLocks.remove(uid); + QWriteLocker lock(&_removeLock); + _laserPointersToRemove.enqueue(uid); } void LaserPointerManager::enableLaserPointer(const unsigned int uid) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->enable(); @@ -57,7 +37,7 @@ void LaserPointerManager::enableLaserPointer(const unsigned int uid) { } void LaserPointerManager::disableLaserPointer(const unsigned int uid) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->disable(); @@ -65,7 +45,7 @@ void LaserPointerManager::disableLaserPointer(const unsigned int uid) { } void LaserPointerManager::setRenderState(unsigned int uid, const QString & renderState) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setRenderState(renderState); @@ -73,7 +53,7 @@ void LaserPointerManager::setRenderState(unsigned int uid, const QString & rende } void LaserPointerManager::editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->editRenderState(state, startProps, pathProps, endProps); @@ -81,7 +61,7 @@ void LaserPointerManager::editRenderState(unsigned int uid, const QString& state } const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QReadLocker laserLock(_laserPointerLocks[uid].get()); return _laserPointers[uid]->getPrevRayPickResult(); @@ -90,16 +70,34 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int } void LaserPointerManager::update() { - QReadLocker lock(&_lock); for (unsigned int uid : _laserPointers.keys()) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts QReadLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->update(); } + + QWriteLocker containsLock(&_containsLock); + { + QWriteLocker lock(&_addLock); + while (!_laserPointersToAdd.isEmpty()) { + QPair> laserPointerToAdd = _laserPointersToAdd.dequeue(); + _laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second; + _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); + } + } + + { + QWriteLocker lock(&_removeLock); + while (!_laserPointersToRemove.isEmpty()) { + unsigned int uid = _laserPointersToRemove.dequeue(); + _laserPointers.remove(uid); + _laserPointerLocks.remove(uid); + } + } } void LaserPointerManager::setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIgnoreEntities(ignoreEntities); @@ -107,7 +105,7 @@ void LaserPointerManager::setIgnoreEntities(unsigned int uid, const QScriptValue } void LaserPointerManager::setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeEntities(includeEntities); @@ -115,7 +113,7 @@ void LaserPointerManager::setIncludeEntities(unsigned int uid, const QScriptValu } void LaserPointerManager::setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIgnoreOverlays(ignoreOverlays); @@ -123,7 +121,7 @@ void LaserPointerManager::setIgnoreOverlays(unsigned int uid, const QScriptValue } void LaserPointerManager::setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeOverlays(includeOverlays); @@ -131,7 +129,7 @@ void LaserPointerManager::setIncludeOverlays(unsigned int uid, const QScriptValu } void LaserPointerManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIgnoreAvatars(ignoreAvatars); @@ -139,7 +137,7 @@ void LaserPointerManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& } void LaserPointerManager::setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { - QReadLocker lock(&_lock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeAvatars(includeAvatars); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index a550de694a..ff63927be2 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -25,12 +25,8 @@ class LaserPointerManager : public Dependency { SINGLETON_DEPENDENCY public: - unsigned int createLaserPointer(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - unsigned int createLaserPointer(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, - const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - unsigned int createLaserPointer(const uint16_t filter, const float maxDistance, const QHash& renderStates, const bool faceAvatar, - const bool centerEndY, const bool lockEnd, const bool enabled); + unsigned int createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, + const bool lockEnd, const bool enabled); void removeLaserPointer(const unsigned int uid); void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); @@ -49,8 +45,13 @@ public: private: QHash> _laserPointers; - QReadWriteLock _lock; QHash> _laserPointerLocks; + unsigned int _nextUID{ 1 }; // 0 is invalid + QReadWriteLock _addLock; + QQueue>> _laserPointersToAdd; + QReadWriteLock _removeLock; + QQueue _laserPointersToRemove; + QReadWriteLock _containsLock; }; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 1cc3a967c4..e1dc1f35c1 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -20,16 +20,6 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { QVariantMap propertyMap = properties.toMap(); - uint16_t filter = 0; - if (propertyMap["filter"].isValid()) { - filter = propertyMap["filter"].toUInt(); - } - - float maxDistance = 0.0f; - if (propertyMap["maxDistance"].isValid()) { - maxDistance = propertyMap["maxDistance"].toFloat(); - } - bool faceAvatar = false; if (propertyMap["faceAvatar"].isValid()) { faceAvatar = propertyMap["faceAvatar"].toBool(); @@ -64,37 +54,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop } } - if (propertyMap["joint"].isValid()) { - QString jointName = propertyMap["joint"].toString(); - - if (jointName != "Mouse") { - // x = upward, y = forward, z = lateral - glm::vec3 posOffset = Vectors::ZERO; - if (propertyMap["posOffset"].isValid()) { - posOffset = vec3FromVariant(propertyMap["posOffset"]); - } - - glm::vec3 dirOffset = Vectors::UP; - if (propertyMap["dirOffset"].isValid()) { - dirOffset = vec3FromVariant(propertyMap["dirOffset"]); - } - - return DependencyManager::get()->createLaserPointer(jointName, posOffset, dirOffset, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); - } else { - return DependencyManager::get()->createLaserPointer(filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); - } - } else if (propertyMap["position"].isValid()) { - glm::vec3 position = vec3FromVariant(propertyMap["position"]); - - glm::vec3 direction = -Vectors::UP; - if (propertyMap["direction"].isValid()) { - direction = vec3FromVariant(propertyMap["direction"]); - } - - return DependencyManager::get()->createLaserPointer(position, direction, filter, maxDistance, renderStates, faceAvatar, centerEndY, lockEnd, enabled); - } - - return 0; + return DependencyManager::get()->createLaserPointer(propertyMap, renderStates, faceAvatar, centerEndY, lockEnd, enabled); } void LaserPointerScriptingInterface::editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) { diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index b7952bfef3..1ccc27f76d 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -19,6 +19,10 @@ #include "scripting/HMDScriptingInterface.h" #include "DependencyManager.h" +#include "JointRayPick.h" +#include "StaticRayPick.h" +#include "MouseRayPick.h" + bool RayPickManager::checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, unsigned int mask) { if (cache.contains(ray) && cache[ray].contains(mask)) { if (cache[ray][mask].distance < res.distance) { @@ -137,10 +141,59 @@ void RayPickManager::update() { } } -unsigned int RayPickManager::addRayPick(std::shared_ptr rayPick) { - QWriteLocker lock(&_addLock); - _rayPicksToAdd.enqueue(QPair>(_nextUID, rayPick)); - return _nextUID++; +unsigned int RayPickManager::createRayPick(const QVariantMap& rayProps) { + bool enabled = false; + if (rayProps["enabled"].isValid()) { + enabled = rayProps["enabled"].toBool(); + } + + uint16_t filter = 0; + if (rayProps["filter"].isValid()) { + filter = rayProps["filter"].toUInt(); + } + + float maxDistance = 0.0f; + if (rayProps["maxDistance"].isValid()) { + maxDistance = rayProps["maxDistance"].toFloat(); + } + + if (rayProps["joint"].isValid()) { + QString jointName = rayProps["joint"].toString(); + + if (jointName != "Mouse") { + // x = upward, y = forward, z = lateral + glm::vec3 posOffset = Vectors::ZERO; + if (rayProps["posOffset"].isValid()) { + posOffset = vec3FromVariant(rayProps["posOffset"]); + } + + glm::vec3 dirOffset = Vectors::UP; + if (rayProps["dirOffset"].isValid()) { + dirOffset = vec3FromVariant(rayProps["dirOffset"]); + } + + QWriteLocker lock(&_addLock); + _rayPicksToAdd.enqueue(QPair>(_nextUID, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); + return _nextUID++; + } else { + QWriteLocker lock(&_addLock); + _rayPicksToAdd.enqueue(QPair>(_nextUID, std::make_shared(filter, maxDistance, enabled))); + return _nextUID++; + } + } else if (rayProps["position"].isValid()) { + glm::vec3 position = vec3FromVariant(rayProps["position"]); + + glm::vec3 direction = -Vectors::UP; + if (rayProps["direction"].isValid()) { + direction = vec3FromVariant(rayProps["direction"]); + } + + QWriteLocker lock(&_addLock); + _rayPicksToAdd.enqueue(QPair>(_nextUID, std::make_shared(position, direction, filter, maxDistance, enabled))); + return _nextUID++; + } + + return 0; } void RayPickManager::removeRayPick(const unsigned int uid) { diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 400098587e..47d982494f 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -58,19 +58,21 @@ class RayPickManager : public QObject, public Dependency { public: void update(); - unsigned int addRayPick(std::shared_ptr rayPick); - void removeRayPick(const unsigned int uid); - void enableRayPick(const unsigned int uid); - void disableRayPick(const unsigned int uid); const PickRay getPickRay(const unsigned int uid); - const RayPickResult getPrevRayPickResult(const unsigned int uid); - void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities); - void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities); - void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays); - void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays); - void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars); - void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars); +public slots: + Q_INVOKABLE unsigned int createRayPick(const QVariantMap& rayProps); + Q_INVOKABLE void removeRayPick(const unsigned int uid); + Q_INVOKABLE void enableRayPick(const unsigned int uid); + Q_INVOKABLE void disableRayPick(const unsigned int uid); + Q_INVOKABLE const RayPickResult getPrevRayPickResult(const unsigned int uid); + + Q_INVOKABLE void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities); + Q_INVOKABLE void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays); + Q_INVOKABLE void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays); + Q_INVOKABLE void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars); + Q_INVOKABLE void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars); private: QHash> _rayPicks; diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 411d5f6e41..a3473df7e3 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -257,12 +257,12 @@ function Grabber() { this.liftKey = false; // SHIFT this.rotateKey = false; // CONTROL - this.mouseRayOverlays = LaserPointers.createLaserPointer({ + this.mouseRayOverlays = RayPick.createRayPick({ joint: "Mouse", filter: RayPick.PICK_OVERLAYS, enabled: true }); - LaserPointers.setIncludeOverlays(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + RayPick.setIncludeOverlays(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); this.mouseRayEntities = LaserPointers.createLaserPointer({ joint: "Mouse", filter: RayPick.PICK_ENTITIES, @@ -318,7 +318,7 @@ Grabber.prototype.pressEvent = function(event) { return; } - var overlayResult = LaserPointers.getPrevRayPickResult(this.mouseRayOverlays); + var overlayResult = RayPick.getPrevRayPickResult(this.mouseRayOverlays); if (overlayResult.type != RayPick.INTERSECTED_NONE) { return; } @@ -572,7 +572,7 @@ Grabber.prototype.keyPressEvent = function(event) { Grabber.prototype.cleanup = function() { LaserPointers.removeLaserPointer(this.mouseRayEntities); - LaserPointers.removeLaserPointer(this.mouseRayOverlays); + RayPick.removeRayPick(this.mouseRayOverlays); }; var grabber = new Grabber(); From 5de0970365c06bc06217c850825cb58b72421bd3 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 20 Jul 2017 14:17:52 -0700 Subject: [PATCH 22/95] put back ignoredEntities functionality in teleport --- scripts/system/controllers/teleport.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index eaeb7767ac..fc22d21089 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -516,6 +516,15 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); +var setIgnoredEntities = function () { + LaserPointers.setIgnoredEntities(teleporter.teleportRayRightVisible, ignoredEntities); + LaserPointers.setIgnoredEntities(teleporter.teleportRayRightInvisible, ignoredEntities); + LaserPointers.setIgnoredEntities(teleporter.teleportRayLeftVisible, ignoredEntities); + LaserPointers.setIgnoredEntities(teleporter.teleportRayLeftInvisible, ignoredEntities); + LaserPointers.setIgnoredEntities(teleporter.teleportRayHeadVisible, ignoredEntities); + LaserPointers.setIgnoredEntities(teleporter.teleportRayHeadInvisible, ignoredEntities); +} + var isDisabled = false; var handleTeleportMessages = function(channel, message, sender) { if (sender === MyAvatar.sessionUUID) { @@ -533,13 +542,13 @@ var handleTeleportMessages = function(channel, message, sender) { isDisabled = false; } } else if (channel === 'Hifi-Teleport-Ignore-Add' && !Uuid.isNull(message) && ignoredEntities.indexOf(message) === -1) { - // TODO: - // add ability to ignore entities to LaserPointers ignoredEntities.push(message); + setIgnoredEntities(); } else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) { var removeIndex = ignoredEntities.indexOf(message); if (removeIndex > -1) { ignoredEntities.splice(removeIndex, 1); + setIgnoredEntities(); } } } From ee02a0bff4ceda83644d3dc4026b7347178ddef0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 24 Jul 2017 12:44:54 -0700 Subject: [PATCH 23/95] fix build error --- interface/src/raypick/LaserPointer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 909e61e00c..359295fd6a 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -49,7 +49,7 @@ private: class LaserPointer { public: - LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, + LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); ~LaserPointer(); From 3c8b964cc9d10cd4e50c9672a0941118303dd497 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 24 Jul 2017 18:16:40 -0700 Subject: [PATCH 24/95] replace setHandLasers with drawHUDLayer overlay property --- interface/resources/shaders/hmd_ui.frag | 27 ++ .../shaders/{hmd_ui_glow.vert => hmd_ui.vert} | 9 +- interface/resources/shaders/hmd_ui_glow.frag | 86 ------- interface/src/Application.cpp | 16 +- .../src/scripting/HMDScriptingInterface.cpp | 60 ++--- .../src/scripting/HMDScriptingInterface.h | 12 +- interface/src/ui/overlays/Circle3DOverlay.cpp | 2 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 2 +- interface/src/ui/overlays/Image3DOverlay.cpp | 2 +- interface/src/ui/overlays/Overlay.cpp | 7 + interface/src/ui/overlays/Overlay.h | 3 + interface/src/ui/overlays/Overlays.cpp | 45 +++- interface/src/ui/overlays/Overlays.h | 5 + interface/src/ui/overlays/Shape3DOverlay.cpp | 2 +- interface/src/ui/overlays/Sphere3DOverlay.cpp | 2 +- .../src/display-plugins/CompositorHelper.cpp | 5 +- .../src/display-plugins/CompositorHelper.h | 3 - .../display-plugins/OpenGLDisplayPlugin.cpp | 9 + .../hmd/DebugHmdDisplayPlugin.cpp | 9 - .../display-plugins/hmd/HmdDisplayPlugin.cpp | 230 +----------------- .../display-plugins/hmd/HmdDisplayPlugin.h | 40 --- libraries/gpu/src/gpu/Frame.h | 2 + libraries/plugins/src/plugins/DisplayPlugin.h | 18 -- .../oculus/src/OculusBaseDisplayPlugin.cpp | 2 - plugins/openvr/src/OpenVrDisplayPlugin.cpp | 3 - .../controllers/handControllerPointer.js | 169 ++++++++++--- 26 files changed, 275 insertions(+), 495 deletions(-) create mode 100644 interface/resources/shaders/hmd_ui.frag rename interface/resources/shaders/{hmd_ui_glow.vert => hmd_ui.vert} (76%) delete mode 100644 interface/resources/shaders/hmd_ui_glow.frag diff --git a/interface/resources/shaders/hmd_ui.frag b/interface/resources/shaders/hmd_ui.frag new file mode 100644 index 0000000000..af96169831 --- /dev/null +++ b/interface/resources/shaders/hmd_ui.frag @@ -0,0 +1,27 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-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 +// + +uniform sampler2D sampler; + +struct OverlayData { + mat4 mvp; + float alpha; +}; + +layout(std140) uniform overlayBuffer { + OverlayData overlay; +}; + +in vec2 vTexCoord; + +out vec4 FragColor; + +void main() { + FragColor = texture(sampler, vTexCoord); + FragColor.a *= overlay.alpha; +} \ No newline at end of file diff --git a/interface/resources/shaders/hmd_ui_glow.vert b/interface/resources/shaders/hmd_ui.vert similarity index 76% rename from interface/resources/shaders/hmd_ui_glow.vert rename to interface/resources/shaders/hmd_ui.vert index 71089d8608..41b9b3666f 100644 --- a/interface/resources/shaders/hmd_ui_glow.vert +++ b/interface/resources/shaders/hmd_ui.vert @@ -8,12 +8,7 @@ struct OverlayData { mat4 mvp; - vec4 glowPoints; - vec4 glowColors[2]; - vec4 resolutionRadiusAlpha; - - vec4 extraGlowColor; - vec2 extraGlowPoint; + float alpha; }; layout(std140) uniform overlayBuffer { @@ -25,11 +20,9 @@ mat4 mvp = overlay.mvp; layout(location = 0) in vec3 Position; layout(location = 3) in vec2 TexCoord; -out vec3 vPosition; out vec2 vTexCoord; void main() { gl_Position = mvp * vec4(Position, 1); vTexCoord = TexCoord; - vPosition = Position; } diff --git a/interface/resources/shaders/hmd_ui_glow.frag b/interface/resources/shaders/hmd_ui_glow.frag deleted file mode 100644 index 5dda76e89d..0000000000 --- a/interface/resources/shaders/hmd_ui_glow.frag +++ /dev/null @@ -1,86 +0,0 @@ -// -// Created by Bradley Austin Davis on 2016/07/11 -// Copyright 2013-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 -// - -uniform sampler2D sampler; - -struct OverlayData { - mat4 mvp; - vec4 glowPoints; - vec4 glowColors[2]; - vec4 resolutionRadiusAlpha; - - vec4 extraGlowColor; - vec2 extraGlowPoint; -}; - -layout(std140) uniform overlayBuffer { - OverlayData overlay; -}; - -vec2 resolution = overlay.resolutionRadiusAlpha.xy; -float radius = overlay.resolutionRadiusAlpha.z; -float alpha = overlay.resolutionRadiusAlpha.w; -vec4 glowPoints = overlay.glowPoints; -vec4 glowColors[2] = overlay.glowColors; - -vec2 extraGlowPoint = overlay.extraGlowPoint; -vec4 extraGlowColor = overlay.extraGlowColor; - -in vec3 vPosition; -in vec2 vTexCoord; - -out vec4 FragColor; - -float easeInOutCubic(float f) { - const float d = 1.0; - const float b = 0.0; - const float c = 1.0; - float t = f; - if ((t /= d / 2.0) < 1.0) return c / 2.0 * t * t * t + b; - return c / 2.0 * ((t -= 2.0) * t * t + 2.0) + b; -} - -void main() { - FragColor = texture(sampler, vTexCoord); - - vec2 aspect = resolution; - aspect /= resolution.x; - - float glowIntensity = 0.0; - float dist1 = distance(vTexCoord * aspect, glowPoints.xy * aspect); - float dist2 = distance(vTexCoord * aspect, glowPoints.zw * aspect); - float dist3 = distance(vTexCoord * aspect, extraGlowPoint * aspect); - float distX = min(dist1, dist2); - float dist = min(distX, dist3); - vec3 glowColor = glowColors[0].rgb; - if (dist2 < dist1) { - glowColor = glowColors[1].rgb; - } - if (dist3 < dist2) { - glowColor = extraGlowColor.rgb; - } - - if (dist <= radius) { - glowIntensity = 1.0 - (dist / radius); - glowColor.rgb = pow(glowColor, vec3(1.0 - glowIntensity)); - glowIntensity = easeInOutCubic(glowIntensity); - glowIntensity = pow(glowIntensity, 0.5); - } - - if (alpha <= 0.0) { - if (glowIntensity <= 0.0) { - discard; - } - - FragColor = vec4(glowColor, glowIntensity); - return; - } - - FragColor.rgb = mix(FragColor.rgb, glowColor.rgb, glowIntensity); - FragColor.a *= alpha; -} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 69835caff0..7a42312f6c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2378,6 +2378,7 @@ void Application::paintGL() { finalFramebuffer = framebufferCache->getFramebuffer(); } + mat4 eyeProjections[2]; { PROFILE_RANGE(render, "/mainRender"); PerformanceTimer perfTimer("mainRender"); @@ -2399,7 +2400,6 @@ void Application::paintGL() { _myCamera.setProjection(displayPlugin->getCullingProjection(_myCamera.getProjection())); renderArgs._context->enableStereo(true); mat4 eyeOffsets[2]; - mat4 eyeProjections[2]; auto baseProjection = renderArgs.getViewFrustum().getProjection(); auto hmdInterface = DependencyManager::get(); float IPDScale = hmdInterface->getIPDScale(); @@ -2430,6 +2430,19 @@ void Application::paintGL() { displaySide(&renderArgs, _myCamera); } + gpu::Batch postCompositeBatch; + { + PROFILE_RANGE(render, "/postComposite"); + PerformanceTimer perfTimer("postComposite"); + renderArgs._batch = &postCompositeBatch; + renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height())); + renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView()); + for_each_eye([&](Eye eye) { + renderArgs._batch->setProjectionTransform(eyeProjections[eye]); + _overlays.render3DHUDOverlays(&renderArgs); + }); + } + auto frame = _gpuContext->endFrame(); frame->frameIndex = _frameCount; frame->framebuffer = finalFramebuffer; @@ -2437,6 +2450,7 @@ void Application::paintGL() { DependencyManager::get()->releaseFramebuffer(framebuffer); }; frame->overlay = _applicationOverlay.getOverlayTexture(); + frame->postCompositeBatch = postCompositeBatch; // deliver final scene rendering commands to the display plugin { PROFILE_RANGE(render, "/pluginOutput"); diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 35f2e2aa86..af3c7c3d67 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -82,6 +82,22 @@ bool HMDScriptingInterface::shouldShowHandControllers() const { return _showHandControllersCount > 0; } +void HMDScriptingInterface::activateHMDHandMouse() { + QWriteLocker lock(&_hmdHandMouseLock); + auto offscreenUi = DependencyManager::get(); + offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", true); + _hmdHandMouseCount++; +} + +void HMDScriptingInterface::deactivateHMDHandMouse() { + QWriteLocker lock(&_hmdHandMouseLock); + _hmdHandMouseCount = std::max(--_hmdHandMouseCount, 0); + if (_hmdHandMouseCount == 0) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", false); + } +} + void HMDScriptingInterface::closeTablet() { _showTablet = false; } @@ -153,50 +169,6 @@ QString HMDScriptingInterface::preferredAudioOutput() const { return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); } -bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) { - if (QThread::currentThread() != thread()) { - bool result; - BLOCKING_INVOKE_METHOD(this, "setHandLasers", Q_RETURN_ARG(bool, result), - Q_ARG(int, hands), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction)); - return result; - } - - auto offscreenUi = DependencyManager::get(); - offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); - return qApp->getActiveDisplayPlugin()->setHandLaser(hands, - enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None, - color, direction); -} - -bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) { - if (QThread::currentThread() != thread()) { - bool result; - BLOCKING_INVOKE_METHOD(this, "setExtraLaser", Q_RETURN_ARG(bool, result), - Q_ARG(glm::vec3, worldStart), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction)); - return result; - } - - auto offscreenUi = DependencyManager::get(); - offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); - - auto myAvatar = DependencyManager::get()->getMyAvatar(); - auto sensorToWorld = myAvatar->getSensorToWorldMatrix(); - auto worldToSensor = glm::inverse(sensorToWorld); - auto sensorStart = ::transformPoint(worldToSensor, worldStart); - auto sensorDirection = ::transformVectorFast(worldToSensor, direction); - - return qApp->getActiveDisplayPlugin()->setExtraLaser(enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None, - color, sensorStart, sensorDirection); -} - -void HMDScriptingInterface::disableExtraLaser() { - setExtraLaser(vec3(0), false, vec4(0), vec3(0)); -} - -void HMDScriptingInterface::disableHandLasers(int hands) { - setHandLasers(hands, false, vec4(0), vec3(0)); -} - bool HMDScriptingInterface::suppressKeyboard() { return qApp->getActiveDisplayPlugin()->suppressKeyboard(); } diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 3ed7db0232..2eefe6ea22 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -22,6 +22,7 @@ class QScriptEngine; #include #include +#include class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency { Q_OBJECT @@ -51,12 +52,8 @@ public: Q_INVOKABLE void requestHideHandControllers(); Q_INVOKABLE bool shouldShowHandControllers() const; - Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction); - Q_INVOKABLE void disableHandLasers(int hands); - - Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction); - Q_INVOKABLE void disableExtraLaser(); - + Q_INVOKABLE void activateHMDHandMouse(); + Q_INVOKABLE void deactivateHMDHandMouse(); /// Suppress the activation of any on-screen keyboard so that a script operation will /// not be interrupted by a keyboard popup @@ -119,6 +116,9 @@ private: bool getHUDLookAtPosition3D(glm::vec3& result) const; glm::mat4 getWorldHMDMatrix() const; std::atomic _showHandControllersCount { 0 }; + + QReadWriteLock _hmdHandMouseLock; + int _hmdHandMouseCount; }; #endif // hifi_HMDScriptingInterface_h diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 827417a912..52a3d7a929 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -267,7 +267,7 @@ const render::ShapeKey Circle3DOverlay::getShapeKey() { if (getAlpha() != 1.0f) { builder.withTranslucent(); } - if (!getIsSolid()) { + if (!getIsSolid() || shouldDrawHUDLayer()) { builder.withUnlit().withDepthBias(); } return builder.build(); diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index a353545245..31cbe5e822 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -120,7 +120,7 @@ const render::ShapeKey Cube3DOverlay::getShapeKey() { if (getAlpha() != 1.0f) { builder.withTranslucent(); } - if (!getIsSolid()) { + if (!getIsSolid() || shouldDrawHUDLayer()) { builder.withUnlit().withDepthBias(); } return builder.build(); diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 7dfee2c491..82417db83a 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -123,7 +123,7 @@ void Image3DOverlay::render(RenderArgs* args) { const render::ShapeKey Image3DOverlay::getShapeKey() { auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); - if (_emissive) { + if (_emissive || shouldDrawHUDLayer()) { builder.withUnlit(); } if (getAlpha() != 1.0f) { diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index b650da3522..868cdf110b 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -29,6 +29,7 @@ Overlay::Overlay() : _alphaPulse(0.0f), _colorPulse(0.0f), _color(DEFAULT_OVERLAY_COLOR), + _drawHUDLayer(false), _visible(true), _anchor(NO_ANCHOR) { @@ -47,6 +48,7 @@ Overlay::Overlay(const Overlay* overlay) : _alphaPulse(overlay->_alphaPulse), _colorPulse(overlay->_colorPulse), _color(overlay->_color), + _drawHUDLayer(overlay->_drawHUDLayer), _visible(overlay->_visible), _anchor(overlay->_anchor) { @@ -86,6 +88,11 @@ void Overlay::setProperties(const QVariantMap& properties) { setColorPulse(properties["colorPulse"].toFloat()); } + if (properties["drawHUDLayer"].isValid()) { + bool drawHUDLayer = properties["drawHUDLayer"].toBool(); + setDrawHUDLayer(drawHUDLayer); + } + if (properties["visible"].isValid()) { bool visible = properties["visible"].toBool(); setVisible(visible); diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 494c287676..0bb0d39d7a 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -58,6 +58,7 @@ public: virtual bool is3D() const = 0; bool isLoaded() { return _isLoaded; } bool getVisible() const { return _visible; } + bool shouldDrawHUDLayer() const { return _drawHUDLayer; } xColor getColor(); float getAlpha(); Anchor getAnchor() const { return _anchor; } @@ -72,6 +73,7 @@ public: // setters void setVisible(bool visible) { _visible = visible; } + void setDrawHUDLayer(bool drawHUDLayer) { _drawHUDLayer = drawHUDLayer; } void setColor(const xColor& color) { _color = color; } void setAlpha(float alpha) { _alpha = alpha; } void setAnchor(Anchor anchor) { _anchor = anchor; } @@ -114,6 +116,7 @@ protected: xColor _color; bool _visible; // should the overlay be drawn at all + bool _drawHUDLayer; // should the overlay be drawn on the HUD layer Anchor _anchor; unsigned int _stackOrder { 0 }; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 72682fcb8c..067bfac0cb 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -37,20 +37,29 @@ #include "Web3DOverlay.h" #include +#include "render/ShapePipeline.h" + Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") +extern void initOverlay3DPipelines(render::ShapePlumber& plumber); + void Overlays::cleanupAllOverlays() { QMap overlaysHUD; + QMap overlays3DHUD; QMap overlaysWorld; { QMutexLocker locker(&_mutex); overlaysHUD.swap(_overlaysHUD); + overlays3DHUD.swap(_overlays3DHUD); overlaysWorld.swap(_overlaysWorld); } foreach(Overlay::Pointer overlay, overlaysHUD) { _overlaysToDelete.push_back(overlay); } + foreach(Overlay::Pointer overlay, overlays3DHUD) { + _overlaysToDelete.push_back(overlay); + } foreach(Overlay::Pointer overlay, overlaysWorld) { _overlaysToDelete.push_back(overlay); } @@ -64,6 +73,8 @@ void Overlays::init() { #if OVERLAY_PANELS _scriptEngine = new QScriptEngine(); #endif + _shapePlumber = std::make_shared(); + initOverlay3DPipelines(*_shapePlumber); } void Overlays::update(float deltatime) { @@ -72,6 +83,9 @@ void Overlays::update(float deltatime) { foreach(const auto& thisOverlay, _overlaysHUD) { thisOverlay->update(deltatime); } + foreach(const auto& thisOverlay, _overlays3DHUD) { + thisOverlay->update(deltatime); + } foreach(const auto& thisOverlay, _overlaysWorld) { thisOverlay->update(deltatime); } @@ -128,6 +142,23 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { } } +void Overlays::render3DHUDOverlays(RenderArgs* renderArgs) { + PROFILE_RANGE(render_overlays, __FUNCTION__); + gpu::Batch& batch = *renderArgs->_batch; + + auto textureCache = DependencyManager::get(); + + QMutexLocker lock(&_mutex); + foreach(Overlay::Pointer thisOverlay, _overlays3DHUD) { + // Reset necessary batch pipeline settings between overlays + batch.setResourceTexture(0, textureCache->getWhiteTexture()); // FIXME - do we really need to do this?? + batch.setModelTransform(Transform()); + + renderArgs->_shapePipeline = _shapePlumber->pickPipeline(renderArgs, thisOverlay->getShapeKey()); + thisOverlay->render(renderArgs); + } +} + void Overlays::disable() { _enabled = false; } @@ -142,8 +173,9 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const { QMutexLocker locker(&_mutex); if (_overlaysHUD.contains(id)) { return _overlaysHUD[id]; - } - if (_overlaysWorld.contains(id)) { + } else if (_overlays3DHUD.contains(id)) { + return _overlays3DHUD[id]; + } else if (_overlaysWorld.contains(id)) { return _overlaysWorld[id]; } return nullptr; @@ -200,7 +232,7 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { OverlayID thisID = OverlayID(QUuid::createUuid()); overlay->setOverlayID(thisID); overlay->setStackOrder(_stackOrder++); - if (overlay->is3D()) { + if (overlay->is3D() && !overlay->shouldDrawHUDLayer()) { { QMutexLocker locker(&_mutex); _overlaysWorld[thisID] = overlay; @@ -210,6 +242,9 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { render::Transaction transaction; overlay->addToScene(overlay, scene, transaction); scene->enqueueTransaction(transaction); + } else if (overlay->is3D() && overlay->shouldDrawHUDLayer()) { + QMutexLocker locker(&_mutex); + _overlays3DHUD[thisID] = overlay; } else { QMutexLocker locker(&_mutex); _overlaysHUD[thisID] = overlay; @@ -294,6 +329,8 @@ void Overlays::deleteOverlay(OverlayID id) { QMutexLocker locker(&_mutex); if (_overlaysHUD.contains(id)) { overlayToDelete = _overlaysHUD.take(id); + } else if (_overlays3DHUD.contains(id)) { + overlayToDelete = _overlays3DHUD.take(id); } else if (_overlaysWorld.contains(id)) { overlayToDelete = _overlaysWorld.take(id); } else { @@ -702,7 +739,7 @@ bool Overlays::isAddedOverlay(OverlayID id) { } QMutexLocker locker(&_mutex); - return _overlaysHUD.contains(id) || _overlaysWorld.contains(id); + return _overlaysHUD.contains(id) || _overlays3DHUD.contains(id) || _overlaysWorld.contains(id); } void Overlays::sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 100f853a96..9efc003669 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -90,6 +90,7 @@ public: void init(); void update(float deltatime); void renderHUD(RenderArgs* renderArgs); + void render3DHUDOverlays(RenderArgs* renderArgs); void disable(); void enable(); @@ -325,7 +326,11 @@ private: mutable QMutex _mutex; QMap _overlaysHUD; + QMap _overlays3DHUD; QMap _overlaysWorld; + + render::ShapePlumberPointer _shapePlumber; + #if OVERLAY_PANELS QMap _panels; #endif diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index a6fcacc769..7126f7bde4 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -65,7 +65,7 @@ const render::ShapeKey Shape3DOverlay::getShapeKey() { if (getAlpha() != 1.0f) { builder.withTranslucent(); } - if (!getIsSolid()) { + if (!getIsSolid() || shouldDrawHUDLayer()) { builder.withUnlit().withDepthBias(); } return builder.build(); diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 5bbf41eb94..ee3f9b9784 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -62,7 +62,7 @@ const render::ShapeKey Sphere3DOverlay::getShapeKey() { if (getAlpha() != 1.0f) { builder.withTranslucent(); } - if (!getIsSolid()) { + if (!getIsSolid() || shouldDrawHUDLayer()) { builder.withUnlit().withDepthBias(); } return builder.build(); diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index 29b8aee08b..4dc8d3378c 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -349,10 +349,9 @@ bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, c auto relativePosition = vec3(relativePosition4) / relativePosition4.w; auto relativeDirection = glm::inverse(glm::quat_cast(UITransform)) * direction; - float uiRadius = _hmdUIRadius; // * myAvatar->getUniformScale(); // FIXME - how do we want to handle avatar scale - + const float UI_RADIUS = 1.0f; // * myAvatar->getUniformScale(); // FIXME - how do we want to handle avatar scale float instersectionDistance; - if (raySphereIntersect(relativeDirection, relativePosition, uiRadius, &instersectionDistance)){ + if (raySphereIntersect(relativeDirection, relativePosition, UI_RADIUS, &instersectionDistance)){ result = position + glm::normalize(direction) * instersectionDistance; return true; } diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index 5be2d68cf9..e6a32dcfb9 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -111,8 +111,6 @@ public: void setDisplayPlugin(const DisplayPluginPointer& displayPlugin) { _currentDisplayPlugin = displayPlugin; } void setFrameInfo(uint32_t frame, const glm::mat4& camera) { _currentCamera = camera; } - float getHmdUiRadius() const { return _hmdUIRadius; } - signals: void allowMouseCaptureChanged(); void alphaChanged(); @@ -142,7 +140,6 @@ private: float _textureAspectRatio { VIRTUAL_UI_ASPECT_RATIO }; float _alpha { 1.0f }; - float _hmdUIRadius { 1.0f }; int _previousBorderWidth { -1 }; int _previousBorderHeight { -1 }; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index e1259fc5fc..1c361ed1ca 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -641,6 +641,15 @@ void OpenGLDisplayPlugin::compositeLayers() { compositePointer(); } + { + PROFILE_RANGE_EX(render_detail, "compositeHUDOverlays", 0xff0077ff, (uint64_t)presentCount()) + render([&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setFramebuffer(_compositeFramebuffer); + }); + _gpuContext->executeBatch(_currentFrame->postCompositeBatch); + } + { PROFILE_RANGE_EX(render_detail, "compositeExtra", 0xff0077ff, (uint64_t)presentCount()) compositeExtra(); diff --git a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp index fd45398236..1e0e7e6c1f 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp @@ -35,16 +35,7 @@ bool DebugHmdDisplayPlugin::beginFrameRender(uint32_t frameIndex) { //_currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose; withNonPresentThreadLock([&] { - _uiModelTransform = DependencyManager::get()->getModelTransform(); _frameInfos[frameIndex] = _currentRenderFrameInfo; - - _handPoses[0] = glm::translate(mat4(), vec3(0.3f * cosf(secTimestampNow() * 3.0f), -0.3f * sinf(secTimestampNow() * 5.0f), 0.0f)); - _handLasers[0].color = vec4(1, 0, 0, 1); - _handLasers[0].mode = HandLaserMode::Overlay; - - _handPoses[1] = glm::translate(mat4(), vec3(0.3f * sinf(secTimestampNow() * 3.0f), -0.3f * cosf(secTimestampNow() * 5.0f), 0.0f)); - _handLasers[1].color = vec4(0, 1, 1, 1); - _handLasers[1].mode = HandLaserMode::Overlay; }); return Parent::beginFrameRender(frameIndex); } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index b183850e7f..fe109e7bc9 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -32,9 +32,6 @@ #include "../Logging.h" #include "../CompositorHelper.h" -#include <../render-utils/shaders/render-utils/glowLine_vert.h> -#include <../render-utils/shaders/render-utils/glowLine_frag.h> - static const QString MONO_PREVIEW = "Mono Preview"; static const QString DISABLE_PREVIEW = "Disable Preview"; @@ -123,26 +120,6 @@ static const int32_t LINE_DATA_SLOT = 1; void HmdDisplayPlugin::customizeContext() { Parent::customizeContext(); _overlayRenderer.build(); - - { - auto state = std::make_shared(); - auto VS = gpu::Shader::createVertex(std::string(glowLine_vert)); - auto PS = gpu::Shader::createPixel(std::string(glowLine_frag)); - auto program = gpu::Shader::createProgram(VS, PS); - state->setCullMode(gpu::State::CULL_NONE); - state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - gpu::Shader::BindingSet bindings; - bindings.insert({ "lineData", LINE_DATA_SLOT });; - gpu::Shader::makeProgram(*program, bindings); - _glowLinePipeline = gpu::Pipeline::create(program, state); - _handLaserUniforms = std::array{ { std::make_shared(), std::make_shared() } }; - _extraLaserUniforms = std::make_shared(); - }; - } void HmdDisplayPlugin::uncustomizeContext() { @@ -157,10 +134,6 @@ void HmdDisplayPlugin::uncustomizeContext() { }); _overlayRenderer = OverlayRenderer(); _previewTexture.reset(); - _handLaserUniforms[0].reset(); - _handLaserUniforms[1].reset(); - _extraLaserUniforms.reset(); - _glowLinePipeline.reset(); Parent::uncustomizeContext(); } @@ -383,132 +356,13 @@ void HmdDisplayPlugin::updateFrameData() { getGLBackend()->setCameraCorrection(correction); } - withPresentThreadLock([&] { - _presentHandLasers = _handLasers; - _presentHandPoses = _handPoses; - _presentUiModelTransform = _uiModelTransform; - - _presentExtraLaser = _extraLaser; - _presentExtraLaserStart = _extraLaserStart; - }); - auto compositorHelper = DependencyManager::get(); glm::mat4 modelMat = compositorHelper->getModelTransform().getMatrix(); - static const float OUT_OF_BOUNDS = -1; - std::array handGlowPoints { { vec2(OUT_OF_BOUNDS), vec2(OUT_OF_BOUNDS) } }; - vec2 extraGlowPoint(OUT_OF_BOUNDS); - - float uiRadius = compositorHelper->getHmdUiRadius(); - - // compute the glow point interesections - for (size_t i = 0; i < NUMBER_OF_HANDS; ++i) { - if (_presentHandPoses[i] == IDENTITY_MATRIX) { - continue; - } - const auto& handLaser = _presentHandLasers[i]; - if (!handLaser.valid()) { - continue; - } - - const vec3& laserDirection = handLaser.direction; - mat4 model = _presentHandPoses[i]; - vec3 castStart = vec3(model[3]); - vec3 castDirection = glm::quat_cast(model) * laserDirection; - - // this offset needs to match GRAB_POINT_SPHERE_OFFSET in scripts/system/libraries/controllers.js:19 - static const vec3 GRAB_POINT_SPHERE_OFFSET(0.04f, 0.13f, 0.039f); // x = upward, y = forward, z = lateral - - // swizzle grab point so that (x = upward, y = lateral, z = forward) - vec3 grabPointOffset = glm::vec3(GRAB_POINT_SPHERE_OFFSET.x, GRAB_POINT_SPHERE_OFFSET.z, -GRAB_POINT_SPHERE_OFFSET.y); - if (i == 0) { - grabPointOffset.x *= -1.0f; // this changes between left and right hands - } - castStart += glm::quat_cast(model) * grabPointOffset; - - // Find the intersection of the laser with he UI and use it to scale the model matrix - float distance; - if (!glm::intersectRaySphere(castStart, castDirection, - _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { - continue; - } - - _presentHandLaserPoints[i].first = castStart; - _presentHandLaserPoints[i].second = _presentHandLaserPoints[i].first + (castDirection * distance); - - vec3 intersectionPosition = castStart + (castDirection * distance) - _presentUiModelTransform.getTranslation(); - intersectionPosition = glm::inverse(_presentUiModelTransform.getRotation()) * intersectionPosition; - - // Take the interesection normal and convert it to a texture coordinate - vec2 yawPitch; - { - vec2 xdir = glm::normalize(vec2(intersectionPosition.x, -intersectionPosition.z)); - yawPitch.x = glm::atan(xdir.x, xdir.y); - yawPitch.y = (acosf(intersectionPosition.y) * -1.0f) + (float)M_PI_2; - } - vec2 halfFov = CompositorHelper::VIRTUAL_UI_TARGET_FOV / 2.0f; - - // Are we out of range - if (glm::any(glm::greaterThan(glm::abs(yawPitch), halfFov))) { - continue; - } - - yawPitch /= CompositorHelper::VIRTUAL_UI_TARGET_FOV; - yawPitch += 0.5f; - handGlowPoints[i] = yawPitch; - } - - // compute the glow point interesections - if (_presentExtraLaser.valid()) { - const vec3& laserDirection = _presentExtraLaser.direction; - vec3 castStart = _presentExtraLaserStart; - vec3 castDirection = laserDirection; - - // Find the intersection of the laser with he UI and use it to scale the model matrix - float distance; - if (glm::intersectRaySphere(castStart, castDirection, - _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { - - - _presentExtraLaserPoints.first = castStart; - _presentExtraLaserPoints.second = _presentExtraLaserPoints.first + (castDirection * distance); - - vec3 intersectionPosition = castStart + (castDirection * distance) - _presentUiModelTransform.getTranslation(); - intersectionPosition = glm::inverse(_presentUiModelTransform.getRotation()) * intersectionPosition; - - // Take the interesection normal and convert it to a texture coordinate - vec2 yawPitch; - { - vec2 xdir = glm::normalize(vec2(intersectionPosition.x, -intersectionPosition.z)); - yawPitch.x = glm::atan(xdir.x, xdir.y); - yawPitch.y = (acosf(intersectionPosition.y) * -1.0f) + (float)M_PI_2; - } - vec2 halfFov = CompositorHelper::VIRTUAL_UI_TARGET_FOV / 2.0f; - - // Are we out of range - if (!glm::any(glm::greaterThan(glm::abs(yawPitch), halfFov))) { - yawPitch /= CompositorHelper::VIRTUAL_UI_TARGET_FOV; - yawPitch += 0.5f; - extraGlowPoint = yawPitch; - } - } - } - for_each_eye([&](Eye eye) { auto modelView = glm::inverse(_currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye)) * modelMat; _overlayRenderer.mvps[eye] = _eyeProjections[eye] * modelView; }); - - // Setup the uniforms - { - auto& uniforms = _overlayRenderer.uniforms; - uniforms.alpha = _compositeOverlayAlpha; - uniforms.glowPoints = vec4(handGlowPoints[0], handGlowPoints[1]); - uniforms.glowColors[0] = _presentHandLasers[0].color; - uniforms.glowColors[1] = _presentHandLasers[1].color; - uniforms.extraGlowPoint = extraGlowPoint; - uniforms.extraGlowColor = _presentExtraLaser.color; - } } void HmdDisplayPlugin::OverlayRenderer::build() { @@ -573,8 +427,8 @@ void HmdDisplayPlugin::OverlayRenderer::build() { } void HmdDisplayPlugin::OverlayRenderer::updatePipeline() { - static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.vert"; - static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.frag"; + static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui.vert"; + static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui.frag"; #if LIVE_SHADER_RELOAD static qint64 vsBuiltAge = 0; @@ -598,7 +452,7 @@ void HmdDisplayPlugin::OverlayRenderer::updatePipeline() { this->uniformsLocation = program->getUniformBuffers().findLocation("overlayBuffer"); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); + state->setDepthTest(gpu::State::DepthTest(true)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); @@ -665,84 +519,6 @@ void HmdDisplayPlugin::compositeOverlay() { _overlayRenderer.render(*this); } -bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const vec4& color, const vec3& direction) { - HandLaserInfo info; - info.mode = mode; - info.color = color; - info.direction = direction; - withNonPresentThreadLock([&] { - if (hands & Hand::LeftHand) { - _handLasers[0] = info; - } - if (hands & Hand::RightHand) { - _handLasers[1] = info; - } - }); - // FIXME defer to a child class plugin to determine if hand lasers are actually - // available based on the presence or absence of hand controllers - return true; -} - -bool HmdDisplayPlugin::setExtraLaser(HandLaserMode mode, const vec4& color, const glm::vec3& sensorSpaceStart, const vec3& sensorSpaceDirection) { - HandLaserInfo info; - info.mode = mode; - info.color = color; - info.direction = sensorSpaceDirection; - withNonPresentThreadLock([&] { - _extraLaser = info; - _extraLaserStart = sensorSpaceStart; - }); - - // FIXME defer to a child class plugin to determine if hand lasers are actually - // available based on the presence or absence of hand controllers - return true; -} - - -void HmdDisplayPlugin::compositeExtra() { - // If neither hand laser is activated, exit - if (!_presentHandLasers[0].valid() && !_presentHandLasers[1].valid() && !_presentExtraLaser.valid()) { - return; - } - - if (_presentHandPoses[0] == IDENTITY_MATRIX && _presentHandPoses[1] == IDENTITY_MATRIX && !_presentExtraLaser.valid()) { - return; - } - - render([&](gpu::Batch& batch) { - batch.setFramebuffer(_compositeFramebuffer); - batch.setModelTransform(Transform()); - batch.setViewportTransform(ivec4(uvec2(0), _renderTargetSize)); - batch.setViewTransform(_currentPresentFrameInfo.presentPose, false); - // Compile the shaders - batch.setPipeline(_glowLinePipeline); - - - bilateral::for_each_side([&](bilateral::Side side){ - auto index = bilateral::index(side); - if (_presentHandPoses[index] == IDENTITY_MATRIX) { - return; - } - const auto& laser = _presentHandLasers[index]; - if (laser.valid()) { - const auto& points = _presentHandLaserPoints[index]; - _handLaserUniforms[index]->resize(sizeof(HandLaserData)); - _handLaserUniforms[index]->setSubData(0, HandLaserData { vec4(points.first, 1.0f), vec4(points.second, 1.0f), _handLasers[index].color }); - batch.setUniformBuffer(LINE_DATA_SLOT, _handLaserUniforms[index]); - batch.draw(gpu::TRIANGLE_STRIP, 4, 0); - } - }); - - if (_presentExtraLaser.valid()) { - const auto& points = _presentExtraLaserPoints; - _extraLaserUniforms->resize(sizeof(HandLaserData)); - _extraLaserUniforms->setSubData(0, HandLaserData { vec4(points.first, 1.0f), vec4(points.second, 1.0f), _presentExtraLaser.color }); - batch.setUniformBuffer(LINE_DATA_SLOT, _extraLaserUniforms); - batch.draw(gpu::TRIANGLE_STRIP, 4, 0); - } - }); -} - HmdDisplayPlugin::~HmdDisplayPlugin() { } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 055328ee21..0827d04922 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -37,9 +37,6 @@ public: virtual glm::mat4 getHeadPose() const override; - bool setHandLaser(uint32_t hands, HandLaserMode mode, const vec4& color, const vec3& direction) override; - bool setExtraLaser(HandLaserMode mode, const vec4& color, const glm::vec3& sensorSpaceStart, const vec3& sensorSpaceDirection) override; - bool wantVsync() const override { return false; } @@ -63,33 +60,6 @@ protected: void customizeContext() override; void uncustomizeContext() override; void updateFrameData() override; - void compositeExtra() override; - - struct HandLaserInfo { - HandLaserMode mode { HandLaserMode::None }; - vec4 color { 1.0f }; - vec3 direction { 0, 0, -1 }; - - // Is this hand laser info suitable for drawing? - bool valid() const { - return (mode != HandLaserMode::None && color.a > 0.0f && direction != vec3()); - } - }; - - Transform _uiModelTransform; - std::array _handLasers; - std::array _handPoses; - - Transform _presentUiModelTransform; - std::array _presentHandLasers; - std::array _presentHandPoses; - std::array, 2> _presentHandLaserPoints; - - HandLaserInfo _extraLaser; - HandLaserInfo _presentExtraLaser; - vec3 _extraLaserStart; - vec3 _presentExtraLaserStart; - std::pair _presentExtraLaserPoints; std::array _eyeOffsets; std::array _eyeProjections; @@ -120,9 +90,6 @@ private: bool _disablePreviewItemAdded { false }; bool _monoPreview { true }; bool _clearPreviewFlag { false }; - std::array _handLaserUniforms; - gpu::BufferPointer _extraLaserUniforms; - gpu::PipelinePointer _glowLinePipeline; gpu::TexturePointer _previewTexture; glm::vec2 _lastWindowSize; @@ -140,14 +107,7 @@ private: struct Uniforms { mat4 mvp; - vec4 glowPoints { -1 }; - vec4 glowColors[2]; - vec2 resolution { CompositorHelper::VIRTUAL_SCREEN_SIZE }; - float radius { 0.005f }; float alpha { 1.0f }; - - vec4 extraGlowColor; - vec2 extraGlowPoint { -1 }; } uniforms; struct Vertex { diff --git a/libraries/gpu/src/gpu/Frame.h b/libraries/gpu/src/gpu/Frame.h index 3c6fed9393..bfebe85753 100644 --- a/libraries/gpu/src/gpu/Frame.h +++ b/libraries/gpu/src/gpu/Frame.h @@ -32,6 +32,8 @@ namespace gpu { Mat4 pose; /// The collection of batches which make up the frame Batches batches; + /// Single batch containing overlays to be drawn in the composite framebuffer + Batch postCompositeBatch; /// The main thread updates to buffers that are applicable for this frame. BufferUpdates bufferUpdates; /// The destination framebuffer in which the results will be placed diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 481a2609fc..398e586ef1 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -107,24 +107,6 @@ public: RightHand = 0x02, }; - enum class HandLaserMode { - None, // Render no hand lasers - Overlay, // Render hand lasers only if they intersect with the UI layer, and stop at the UI layer - }; - - virtual bool setHandLaser( - uint32_t hands, // Bits from the Hand enum - HandLaserMode mode, // Mode in which to render - const vec4& color = vec4(1), // The color of the rendered laser - const vec3& direction = vec3(0, 0, -1) // The direction in which to render the hand lasers - ) { - return false; - } - - virtual bool setExtraLaser(HandLaserMode mode, const vec4& color, const glm::vec3& sensorSpaceStart, const vec3& sensorSpaceDirection) { - return false; - } - virtual bool suppressKeyboard() { return false; } virtual void unsuppressKeyboard() {}; virtual bool isKeyboardVisible() { return false; } diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 93f4787f0f..426c162628 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -51,8 +51,6 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { }); withNonPresentThreadLock([&] { - _uiModelTransform = DependencyManager::get()->getModelTransform(); - _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; }); return Parent::beginFrameRender(frameIndex); diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 7a73c91c7d..394125a734 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -594,9 +594,6 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { } withNonPresentThreadLock([&] { - _uiModelTransform = DependencyManager::get()->getModelTransform(); - // Make controller poses available to the presentation thread - _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; }); return Parent::beginFrameRender(frameIndex); diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index eb94428100..f169204206 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -150,15 +150,92 @@ var setReticlePosition = function (point2d) { Reticle.setPosition(point2d); }; -// Generalizations of utilities that work with system and overlay elements. -function findRayIntersection(pickRay) { - // Check 3D overlays and entities. Argument is an object with origin and direction. - var result = Overlays.findRayIntersection(pickRay); - if (!result.intersects) { - result = Entities.findRayIntersection(pickRay, true); - } - return result; +// VISUAL AID ----------- +// Same properties as handControllerGrab search sphere +var LASER_ALPHA = 0.5; +var LASER_SEARCH_COLOR = {red: 10, green: 10, blue: 255}; +var LASER_TRIGGER_COLOR = {red: 250, green: 10, blue: 10}; +var END_DIAMETER = 0.05; +var systemLaserOn = false; + +var triggerPath = { + type: "line3d", + color: LASER_SEARCH_COLOR, + ignoreRayIntersection: true, + visible: true, + alpha: LASER_ALPHA, + solid: true, + glow: 1.0, + drawHUDLayer: true } +var triggerEnd = { + type: "sphere", + dimensions: {x: END_DIAMETER, y: END_DIAMETER, z: END_DIAMETER}, + color: LASER_SEARCH_COLOR, + ignoreRayIntersection: true, + visible: true, + alpha: LASER_ALPHA, + solid: true, + drawHUDLayer: true +} + +var searchPath = { + type: "line3d", + color: LASER_TRIGGER_COLOR, + ignoreRayIntersection: true, + visible: true, + alpha: LASER_ALPHA, + solid: true, + glow: 1.0, + drawHUDLayer: true +} +var searchEnd = { + type: "sphere", + dimensions: {x: END_DIAMETER, y: END_DIAMETER, z: END_DIAMETER}, + color: LASER_TRIGGER_COLOR, + ignoreRayIntersection: true, + visible: true, + alpha: LASER_ALPHA, + solid: true, + drawHUDLayer: true +} + +var hudRayStates = [{name: "trigger", path: triggerPath, end: triggerEnd}, + {name: "search", path: searchPath, end: searchEnd}]; +// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378 +var GRAB_POINT_SPHERE_OFFSET_RIGHT = { x: 0.04, y: 0.13, z: 0.039 }; +var GRAB_POINT_SPHERE_OFFSET_LEFT = { x: -0.04, y: 0.13, z: 0.039 }; +var hudRayRight = LaserPointers.createLaserPointer({ + joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", + filter: RayPick.PICK_HUD, + posOffset: GRAB_POINT_SPHERE_OFFSET_RIGHT, + renderStates: hudRayStates, + enabled: true +}); +var hudRayLeft = LaserPointers.createLaserPointer({ + joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + filter: RayPick.PICK_HUD, + posOffset: GRAB_POINT_SPHERE_OFFSET_LEFT, + renderStates: hudRayStates, + enabled: true +}); + +// NOTE: keep this offset in sync with scripts/system/librarires/controllers.js:57 +var VERTICAL_HEAD_LASER_OFFSET = 0.1; +var hudRayHead = LaserPointers.createLaserPointer({ + joint: "Avatar", + filter: RayPick.PICK_HUD, + posOffset: {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0}, + renderStates: hudRayStates, + enabled: true +}); + +var mouseRayPick = RayPick.createRayPick({ + joint: "Mouse", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + enabled: true +}); + function isPointingAtOverlay(optionalHudPosition2d) { return Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(optionalHudPosition2d || Reticle.position); } @@ -166,10 +243,21 @@ function isPointingAtOverlay(optionalHudPosition2d) { // Generalized HUD utilities, with or without HMD: // This "var" is for documentation. Do not change the value! var PLANAR_PERPENDICULAR_HUD_DISTANCE = 1; -function calculateRayUICollisionPoint(position, direction) { +function calculateRayUICollisionPoint(position, direction, isHands) { // Answer the 3D intersection of the HUD by the given ray, or falsey if no intersection. if (HMD.active) { - return HMD.calculateRayUICollisionPoint(position, direction); + var laserPointer; + if (isHands) { + laserPointer = activeHand == Controller.Standard.RightHand ? hudRayRight : hudRayLeft; + } else { + laserPointer = hudRayHead; + } + var result = LaserPointers.getPrevRayPickResult(laserPointer); + if (result.type != RayPick.INTERSECTED_NONE) { + return result.intersection; + } else { + return null; + } } // interect HUD plane, 1m in front of camera, using formula: // scale = hudNormal dot (hudPoint - position) / hudNormal dot direction @@ -215,7 +303,7 @@ function activeHudPoint2dGamePad() { var headPosition = MyAvatar.getHeadPosition(); var headDirection = Quat.getUp(Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }))); - var hudPoint3d = calculateRayUICollisionPoint(headPosition, headDirection); + var hudPoint3d = calculateRayUICollisionPoint(headPosition, headDirection, false); if (!hudPoint3d) { if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here @@ -241,7 +329,7 @@ function activeHudPoint2d(activeHand) { // if controller is valid, update reticl var controllerPosition = controllerPose.position; var controllerDirection = Quat.getUp(controllerPose.rotation); - var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection); + var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection, true); if (!hudPoint3d) { if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here print('Controller is parallel to HUD'); // so let us know that our assumptions are wrong. @@ -355,7 +443,7 @@ function onMouseMove() { if (isPointingAtOverlay()) { Reticle.depth = hudReticleDistance(); } else { - var result = findRayIntersection(Camera.computePickRay(Reticle.position.x, Reticle.position.y)); + var result = RayPick.getPrevRayPickResult(mouseRayPick); Reticle.depth = result.intersects ? result.distance : APPARENT_MAXIMUM_DEPTH; } } @@ -473,14 +561,6 @@ clickMapping.from(rightTrigger.partial).to(makeToggleAction(Controller.Standard. clickMapping.from(leftTrigger.partial).to(makeToggleAction(Controller.Standard.LeftHand)); clickMapping.enable(); -// VISUAL AID ----------- -// Same properties as handControllerGrab search sphere -var LASER_ALPHA = 0.5; -var LASER_SEARCH_COLOR_XYZW = {x: 10 / 255, y: 10 / 255, z: 255 / 255, w: LASER_ALPHA}; -var LASER_TRIGGER_COLOR_XYZW = {x: 250 / 255, y: 10 / 255, z: 10 / 255, w: LASER_ALPHA}; -var SYSTEM_LASER_DIRECTION = {x: 0, y: 0, z: -1}; -var systemLaserOn = false; - var HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable"; var isPointerEnabled = true; @@ -488,23 +568,34 @@ function clearSystemLaser() { if (!systemLaserOn) { return; } - HMD.disableHandLasers(BOTH_HUD_LASERS); - HMD.disableExtraLaser(); + HMD.deactivateHMDHandMouse(); + LaserPointers.setRenderState(hudRayRight, ""); + LaserPointers.setRenderState(hudRayLeft, ""); + LaserPointers.setRenderState(hudRayHead, ""); systemLaserOn = false; weMovedReticle = true; } function setColoredLaser() { // answer trigger state if lasers supported, else falsey. - var color = (activeTrigger.state === 'full') ? LASER_TRIGGER_COLOR_XYZW : LASER_SEARCH_COLOR_XYZW; + var mode = (activeTrigger.state === 'full') ? 'trigger' : 'search'; - if (!HMD.isHandControllerAvailable()) { - // NOTE: keep this offset in sync with scripts/system/librarires/controllers.js:57 - var VERTICAL_HEAD_LASER_OFFSET = 0.1; - var position = Vec3.sum(HMD.position, Vec3.multiplyQbyV(HMD.orientation, {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0})); - var orientation = Quat.multiply(HMD.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 })); - return HMD.setExtraLaser(position, true, color, Quat.getUp(orientation)); + if (!systemLaserOn) { + HMD.activateHMDHandMouse(); } - return HMD.setHandLasers(activeHudLaser, true, color, SYSTEM_LASER_DIRECTION) && activeTrigger.state; + var pose = Controller.getPoseValue(activeHand); + if (!pose.valid) { + LaserPointers.setRenderState(hudRayRight, ""); + LaserPointers.setRenderState(hudRayLeft, ""); + LaserPointers.setRenderState(hudRayHead, mode); + return true; + } + + var right = activeHand == Controller.Standard.RightHand; + LaserPointers.setRenderState(hudRayRight, right ? mode : ""); + LaserPointers.setRenderState(hudRayLeft, right ? "" : mode); + LaserPointers.setRenderState(hudRayHead, ""); + + return activeTrigger.state; } // MAIN OPERATIONS ----------- @@ -551,11 +642,13 @@ function update() { if (HMD.active) { Reticle.depth = hudReticleDistance(); - if (!HMD.isHandControllerAvailable()) { - var color = (activeTrigger.state === 'full') ? LASER_TRIGGER_COLOR_XYZW : LASER_SEARCH_COLOR_XYZW; - var position = MyAvatar.getHeadPosition(); - var direction = Quat.getUp(Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }))); - HMD.setExtraLaser(position, true, color, direction); + var pose = Controller.getPoseValue(activeHand); + if (!pose.valid) { + var mode = (activeTrigger.state === 'full') ? 'trigger' : 'search'; + if (!systemLaserOn) { + HMD.activateHMDHandMouse(); + } + LaserPointers.setRenderState(hudRayHead, mode); } } @@ -604,6 +697,10 @@ Script.scriptEnding.connect(function () { Script.clearInterval(settingsChecker); Script.update.disconnect(update); OffscreenFlags.navigationFocusDisabled = false; + LaserPointers.removeLaserPointer(hudRayRight); + LaserPointers.removeLaserPointer(hudRayLeft); + LaserPointers.removeLaserPointer(hudRayHead); + HMD.deactivateHMDHandMouse(); }); }()); // END LOCAL_SCOPE From f128dce185905cf930813f1611c119ba7df423b1 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Mon, 24 Jul 2017 17:10:45 -0700 Subject: [PATCH 25/95] Changed marketplaces message to be more discoverable --- scripts/system/html/js/marketplacesInject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 3b3d4b4937..45b2e99018 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -57,7 +57,7 @@ $("body").append( '
' + (!isInitialHiFiPage ? '' : '') + - (isInitialHiFiPage ? '🛈 See also other marketplaces.' : '') + + (isInitialHiFiPage ? '🛈 Get items from Blocks and Clara.io!' : '') + (!isDirectoryPage ? '' : '') + (isDirectoryPage ? '🛈 Select a marketplace to explore.' : '') + '
' From 3149c3e16c0671a8428390b28e3614f3ca170c90 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 25 Jul 2017 10:16:50 -0700 Subject: [PATCH 26/95] warnings --- interface/src/scripting/HMDScriptingInterface.cpp | 2 +- interface/src/ui/overlays/Overlay.cpp | 4 ++-- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 9 --------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index af3c7c3d67..93c3a7652e 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -91,7 +91,7 @@ void HMDScriptingInterface::activateHMDHandMouse() { void HMDScriptingInterface::deactivateHMDHandMouse() { QWriteLocker lock(&_hmdHandMouseLock); - _hmdHandMouseCount = std::max(--_hmdHandMouseCount, 0); + _hmdHandMouseCount = std::max(_hmdHandMouseCount - 1, 0); if (_hmdHandMouseCount == 0) { auto offscreenUi = DependencyManager::get(); offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", false); diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 868cdf110b..3afe7d76ca 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -29,8 +29,8 @@ Overlay::Overlay() : _alphaPulse(0.0f), _colorPulse(0.0f), _color(DEFAULT_OVERLAY_COLOR), - _drawHUDLayer(false), _visible(true), + _drawHUDLayer(false), _anchor(NO_ANCHOR) { } @@ -48,8 +48,8 @@ Overlay::Overlay(const Overlay* overlay) : _alphaPulse(overlay->_alphaPulse), _colorPulse(overlay->_colorPulse), _color(overlay->_color), - _drawHUDLayer(overlay->_drawHUDLayer), _visible(overlay->_visible), + _drawHUDLayer(overlay->_drawHUDLayer), _anchor(overlay->_anchor) { } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index fe109e7bc9..ab53316010 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -42,17 +42,10 @@ static const bool DEFAULT_MONO_VIEW = true; static const bool DEFAULT_DISABLE_PREVIEW = false; #endif static const glm::mat4 IDENTITY_MATRIX; -static const size_t NUMBER_OF_HANDS = 2; //#define LIVE_SHADER_RELOAD 1 extern glm::vec3 getPoint(float yaw, float pitch); -struct HandLaserData { - vec4 p1; - vec4 p2; - vec4 color; -}; - static QString readFile(const QString& filename) { QFile file(filename); file.open(QFile::Text | QFile::ReadOnly); @@ -115,8 +108,6 @@ void HmdDisplayPlugin::internalDeactivate() { Parent::internalDeactivate(); } -static const int32_t LINE_DATA_SLOT = 1; - void HmdDisplayPlugin::customizeContext() { Parent::customizeContext(); _overlayRenderer.build(); From 3189cb90e43f431bd99fb01503160c4ec9660156 Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Tue, 25 Jul 2017 15:20:11 -0400 Subject: [PATCH 27/95] Address bug #21448 "Correctly Size Bounding Boxes for Polylines" Changed PloyLineEntity code to calculate the scale vector (which PolyLineEntity uses as the bouding box) and the registration point (the offset of the bounding box from the first point in the Polyline) based on the points in the PolyLineEntity so the bounding box is just big enough to contain all the points in the line. --- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 77 +++++++++++++++---- libraries/entities/src/PolyLineEntityItem.h | 9 ++- 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 92c83651aa..062f9cb2ed 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -262,7 +262,7 @@ public: glm::vec3 getRegistrationPoint() const; /// registration point as ratio of entity /// registration point as ratio of entity - void setRegistrationPoint(const glm::vec3& value); + virtual void setRegistrationPoint(const glm::vec3& value); bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalAngularVelocity() const { return getLocalAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index c1f6508a76..e8cce8b4e6 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -92,13 +92,12 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { qCDebug(entities) << "MAX POINTS REACHED!"; return false; } - glm::vec3 halfBox = getDimensions() * 0.5f; - if ((point.x < -halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < -halfBox.z || point.z > halfBox.z)) { - qCDebug(entities) << "Point is outside entity's bounding box"; - return false; - } + _points << point; _pointsChanged = true; + + calculateScaleAndRegistrationPoint(); + return true; } @@ -141,23 +140,71 @@ bool PolyLineEntityItem::setLinePoints(const QVector& points) { return; } - for (int i = 0; i < points.size(); i++) { - glm::vec3 point = points.at(i); - glm::vec3 halfBox = getDimensions() * 0.5f; - if ((point.x < -halfBox.x || point.x > halfBox.x) || - (point.y < -halfBox.y || point.y > halfBox.y) || - (point.z < -halfBox.z || point.z > halfBox.z)) { - qCDebug(entities) << "Point is outside entity's bounding box"; - return; - } - } _points = points; + + calculateScaleAndRegistrationPoint(); + result = true; }); return result; } +void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { + glm::vec3 high(0.0f, 0.0f, 0.0f); + glm::vec3 low(0.0f, 0.0f, 0.0f); + for (int i = 0; i < _points.size(); i++) { + glm::vec3 point = _points.at(i); + + if (point.x > high.x){ + high.x = point.x; + } + else if (point.x < low.x) { + low.x = point.x; + } + + if (point.y > high.y){ + high.y = point.y; + } + else if (point.y < low.y) { + low.y = point.y; + } + + if (point.z > high.z){ + high.z = point.z; + } + else if (point.z < low.z) { + low.z = point.z; + } + } + + if (_points.size() > 1) { + // if all the points in the Polyline are at the same place in space, use default dimension settings + if ((low - high).length() < 0.00001f) { + SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); + EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); + return; + } + + glm::vec3 result; + result.x = abs(high.x) + abs(low.x); + result.y = abs(high.y) + abs(low.y); + result.z = abs(high.z) + abs(low.z); + SpatiallyNestable::setScale(result); + + glm::vec3 point = _points.at(0); + glm::vec3 startPointInScaleSpace = point - low; + glm::vec3 newRegistrationPoint = startPointInScaleSpace / result; + EntityItem::setRegistrationPoint(newRegistrationPoint); + } + else { + // if Polyline has only one or fewer points, use default dimension settings + SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); + EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); + return; + } +} + int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index ed161762fc..eca9a1ec79 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -81,10 +81,17 @@ class PolyLineEntityItem : public EntityItem { BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override { return false; } + // disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain + virtual void setRegistrationPoint(const glm::vec3& value) override {}; + virtual void setScale(const glm::vec3& scale) override {}; + virtual void setScale(float value) override {}; + virtual void debugDump() const override; static const float DEFAULT_LINE_WIDTH; static const int MAX_POINTS_PER_LINE; - +private: + void calculateScaleAndRegistrationPoint(); + protected: rgbColor _color; float _lineWidth; From 011795054652898eee287d85d10b9e98b9b1daf9 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 25 Jul 2017 12:57:52 -0700 Subject: [PATCH 28/95] can edit drawHUDLayer property --- interface/src/ui/overlays/Overlay.cpp | 8 +++++++ interface/src/ui/overlays/Overlay.h | 2 +- interface/src/ui/overlays/Overlays.cpp | 22 +++++++++++++++++++ interface/src/ui/overlays/Overlays.h | 2 ++ .../display-plugins/OpenGLDisplayPlugin.cpp | 3 ++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 3afe7d76ca..541c251371 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -13,6 +13,8 @@ #include #include +#include "Application.h" + static const xColor DEFAULT_OVERLAY_COLOR = { 255, 255, 255 }; static const float DEFAULT_ALPHA = 0.7f; @@ -168,6 +170,12 @@ float Overlay::getAlpha() { return (_alphaPulse >= 0.0f) ? _alpha * pulseLevel : _alpha * (1.0f - pulseLevel); } +void Overlay::setDrawHUDLayer(bool drawHUDLayer) { + if (drawHUDLayer != _drawHUDLayer) { + qApp->getOverlays().setOverlayDrawHUDLayer(getOverlayID(), drawHUDLayer); + _drawHUDLayer = drawHUDLayer; + } +} // pulse travels from min to max, then max to min in one period. float Overlay::updatePulse() { diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 0bb0d39d7a..a9774eea06 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -73,7 +73,7 @@ public: // setters void setVisible(bool visible) { _visible = visible; } - void setDrawHUDLayer(bool drawHUDLayer) { _drawHUDLayer = drawHUDLayer; } + void setDrawHUDLayer(bool drawHUDLayer); void setColor(const xColor& color) { _color = color; } void setAlpha(float alpha) { _alpha = alpha; } void setAnchor(Anchor anchor) { _anchor = anchor; } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 067bfac0cb..5d6029f521 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -253,6 +253,28 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { return thisID; } +void Overlays::setOverlayDrawHUDLayer(const OverlayID& id, const bool drawHUDLayer) { + QMutexLocker locker(&_mutex); + if (drawHUDLayer && _overlaysWorld.contains(id)) { + std::shared_ptr overlay = _overlaysWorld.take(id); + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + auto itemID = overlay->getRenderItemID(); + if (render::Item::isValidID(itemID)) { + overlay->removeFromScene(overlay, scene, transaction); + scene->enqueueTransaction(transaction); + } + _overlays3DHUD[id] = overlay; + } else if (!drawHUDLayer && _overlays3DHUD.contains(id)) { + std::shared_ptr overlay = _overlays3DHUD.take(id); + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + overlay->addToScene(overlay, scene, transaction); + scene->enqueueTransaction(transaction); + _overlaysWorld[id] = overlay; + } +} + OverlayID Overlays::cloneOverlay(OverlayID id) { if (QThread::currentThread() != thread()) { OverlayID result; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 9efc003669..8aa15d7f14 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -103,6 +103,8 @@ public: OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } OverlayID addOverlay(const Overlay::Pointer& overlay); + void setOverlayDrawHUDLayer(const OverlayID& id, const bool drawHUDLayer); + bool mousePressEvent(QMouseEvent* event); bool mouseDoublePressEvent(QMouseEvent* event); bool mouseReleaseEvent(QMouseEvent* event); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 1c361ed1ca..7333c7012c 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -641,7 +641,8 @@ void OpenGLDisplayPlugin::compositeLayers() { compositePointer(); } - { + // Only render HUD layer 3D overlays in HMD mode + if (isHmd()) { PROFILE_RANGE_EX(render_detail, "compositeHUDOverlays", 0xff0077ff, (uint64_t)presentCount()) render([&](gpu::Batch& batch) { batch.enableStereo(false); From 0c03b4ec53bd799eed02681c3805d24702612bcf Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Tue, 25 Jul 2017 16:37:40 -0400 Subject: [PATCH 29/95] Use fabsf() instead of abs() so Clang doesn't default to int abs() --- libraries/entities/src/PolyLineEntityItem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index e8cce8b4e6..c698e6d5dd 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -177,19 +177,19 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { low.z = point.z; } } - + const float EPSILON = 0.0001f; if (_points.size() > 1) { // if all the points in the Polyline are at the same place in space, use default dimension settings - if ((low - high).length() < 0.00001f) { + if ((low - high).length() < EPSILON) { SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); return; } glm::vec3 result; - result.x = abs(high.x) + abs(low.x); - result.y = abs(high.y) + abs(low.y); - result.z = abs(high.z) + abs(low.z); + result.x = fabsf(high.x) + fabsf(low.x); + result.y = fabsf(high.y) + fabsf(low.y); + result.z = fabsf(high.z) + fabsf(low.z); SpatiallyNestable::setScale(result); glm::vec3 point = _points.at(0); From 658acd91f2fdb30be4b134869294c3094f9d58f3 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 25 Jul 2017 14:17:39 -0700 Subject: [PATCH 30/95] experimenting with drawHUDLayer depth testing --- interface/resources/shaders/hmd_ui.frag | 3 +++ interface/src/ui/overlays/Overlays.cpp | 4 +-- .../display-plugins/OpenGLDisplayPlugin.cpp | 26 ++++++++++++++----- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderPipelines.cpp | 10 ++++--- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/interface/resources/shaders/hmd_ui.frag b/interface/resources/shaders/hmd_ui.frag index af96169831..5341ab575d 100644 --- a/interface/resources/shaders/hmd_ui.frag +++ b/interface/resources/shaders/hmd_ui.frag @@ -24,4 +24,7 @@ out vec4 FragColor; void main() { FragColor = texture(sampler, vTexCoord); FragColor.a *= overlay.alpha; + if (FragColor.a <= 0.0) { + discard; + } } \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5d6029f521..197ea907da 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -41,7 +41,7 @@ Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") -extern void initOverlay3DPipelines(render::ShapePlumber& plumber); +extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false); void Overlays::cleanupAllOverlays() { QMap overlaysHUD; @@ -74,7 +74,7 @@ void Overlays::init() { _scriptEngine = new QScriptEngine(); #endif _shapePlumber = std::make_shared(); - initOverlay3DPipelines(*_shapePlumber); + initOverlay3DPipelines(*_shapePlumber, true); } void Overlays::update(float deltatime) { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 7333c7012c..db7c0e4f65 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -626,6 +626,11 @@ void OpenGLDisplayPlugin::compositeLayers() { compositeScene(); } + // Clear the depth framebuffer after drawing the scene so that the HUD elements can depth test against each other + render([&](gpu::Batch& batch) { + batch.setFramebuffer(_compositeFramebuffer); + batch.clearDepthFramebuffer(UINT32_MAX); + }); #ifdef HIFI_ENABLE_NSIGHT_DEBUG if (false) // do not compositeoverlay if running nsight debug @@ -635,12 +640,6 @@ void OpenGLDisplayPlugin::compositeLayers() { compositeOverlay(); } - auto compositorHelper = DependencyManager::get(); - if (compositorHelper->getReticleVisible()) { - PROFILE_RANGE_EX(render_detail, "compositePointer", 0xff0077ff, (uint64_t)presentCount()) - compositePointer(); - } - // Only render HUD layer 3D overlays in HMD mode if (isHmd()) { PROFILE_RANGE_EX(render_detail, "compositeHUDOverlays", 0xff0077ff, (uint64_t)presentCount()) @@ -655,6 +654,18 @@ void OpenGLDisplayPlugin::compositeLayers() { PROFILE_RANGE_EX(render_detail, "compositeExtra", 0xff0077ff, (uint64_t)presentCount()) compositeExtra(); } + + // Clear the depth buffer again and draw the pointer last so it's on top of everything + render([&](gpu::Batch& batch) { + batch.setFramebuffer(_compositeFramebuffer); + batch.clearDepthFramebuffer(UINT32_MAX); + }); + + auto compositorHelper = DependencyManager::get(); + if (compositorHelper->getReticleVisible()) { + PROFILE_RANGE_EX(render_detail, "compositePointer", 0xff0077ff, (uint64_t)presentCount()) + compositePointer(); + } } void OpenGLDisplayPlugin::internalPresent() { @@ -861,7 +872,8 @@ OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { void OpenGLDisplayPlugin::updateCompositeFramebuffer() { auto renderSize = getRecommendedRenderSize(); if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) { - _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y)); + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); + _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, depthFormat, renderSize.x, renderSize.y)); } } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index ab53316010..aef5c73fa3 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -443,7 +443,7 @@ void HmdDisplayPlugin::OverlayRenderer::updatePipeline() { this->uniformsLocation = program->getUniformBuffers().findLocation("overlayBuffer"); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(true)); + state->setDepthTest(gpu::State::DepthTest(true, true, gpu::LESS_EQUAL)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 20c999019b..94fd1627d6 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -44,7 +44,7 @@ using namespace render; -extern void initOverlay3DPipelines(render::ShapePlumber& plumber); +extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false); extern void initDeferredPipelines(render::ShapePlumber& plumber); void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 6c3a58b7e5..18146ca651 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -69,7 +69,7 @@ using namespace render; using namespace std::placeholders; -void initOverlay3DPipelines(ShapePlumber& plumber); +void initOverlay3DPipelines(ShapePlumber& plumber, bool depthTest = false); void initDeferredPipelines(ShapePlumber& plumber); void initForwardPipelines(ShapePlumber& plumber); @@ -79,7 +79,7 @@ void addPlumberPipeline(ShapePlumber& plumber, void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args); void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args); -void initOverlay3DPipelines(ShapePlumber& plumber) { +void initOverlay3DPipelines(ShapePlumber& plumber, bool depthTest) { auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); auto vertexModel = gpu::Shader::createVertex(std::string(model_vert)); auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag)); @@ -106,7 +106,11 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { bool isOpaque = (i & 4); auto state = std::make_shared(); - state->setDepthTest(false); + if (depthTest) { + state->setDepthTest(true, true, gpu::LESS_EQUAL); + } else { + state->setDepthTest(false); + } state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); if (isBiased) { state->setDepthBias(1.0f); From 3a8ad8b6318e629826d341df05a52da5f217dc0a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 25 Jul 2017 15:11:44 -0700 Subject: [PATCH 31/95] switch to QUuids --- interface/src/raypick/LaserPointer.h | 4 +- interface/src/raypick/LaserPointerManager.cpp | 39 +++++++++-------- interface/src/raypick/LaserPointerManager.h | 35 ++++++++------- .../LaserPointerScriptingInterface.cpp | 4 +- .../raypick/LaserPointerScriptingInterface.h | 26 +++++------ interface/src/raypick/RayPickManager.cpp | 43 ++++++++++--------- interface/src/raypick/RayPickManager.h | 33 +++++++------- 7 files changed, 93 insertions(+), 91 deletions(-) diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 359295fd6a..b1b8be23e4 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -53,7 +53,7 @@ public: const bool lockEnd, const bool enabled); ~LaserPointer(); - unsigned int getRayUID() { return _rayPickUID; } + QUuid getRayUID() { return _rayPickUID; } void enable(); void disable(); const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } @@ -78,7 +78,7 @@ private: bool _centerEndY; bool _lockEnd; - unsigned int _rayPickUID; + QUuid _rayPickUID; OverlayID updateRenderStateOverlay(const OverlayID& id, const QVariant& props); void disableRenderState(const QString& renderState); diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index d9f3023263..2b4d7d096b 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -12,23 +12,24 @@ #include "LaserPointer.h" #include "RayPick.h" -unsigned int LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, +QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, faceAvatar, centerEndY, lockEnd, enabled); if (laserPointer->getRayUID() != 0) { QWriteLocker lock(&_addLock); - _laserPointersToAdd.enqueue(QPair>(_nextUID, laserPointer)); - return _nextUID++; + QUuid id = QUuid::createUuid(); + _laserPointersToAdd.enqueue(QPair>(id, laserPointer)); + return id; } - return 0; + return QUuid(); } -void LaserPointerManager::removeLaserPointer(const unsigned int uid) { +void LaserPointerManager::removeLaserPointer(const QUuid uid) { QWriteLocker lock(&_removeLock); _laserPointersToRemove.enqueue(uid); } -void LaserPointerManager::enableLaserPointer(const unsigned int uid) { +void LaserPointerManager::enableLaserPointer(const QUuid uid) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -36,7 +37,7 @@ void LaserPointerManager::enableLaserPointer(const unsigned int uid) { } } -void LaserPointerManager::disableLaserPointer(const unsigned int uid) { +void LaserPointerManager::disableLaserPointer(const QUuid uid) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -44,7 +45,7 @@ void LaserPointerManager::disableLaserPointer(const unsigned int uid) { } } -void LaserPointerManager::setRenderState(unsigned int uid, const QString & renderState) { +void LaserPointerManager::setRenderState(QUuid uid, const QString & renderState) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -52,7 +53,7 @@ void LaserPointerManager::setRenderState(unsigned int uid, const QString & rende } } -void LaserPointerManager::editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { +void LaserPointerManager::editRenderState(QUuid uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -60,7 +61,7 @@ void LaserPointerManager::editRenderState(unsigned int uid, const QString& state } } -const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { +const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QReadLocker laserLock(_laserPointerLocks[uid].get()); @@ -70,7 +71,7 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const unsigned int } void LaserPointerManager::update() { - for (unsigned int uid : _laserPointers.keys()) { + for (QUuid uid : _laserPointers.keys()) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts QReadLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->update(); @@ -80,7 +81,7 @@ void LaserPointerManager::update() { { QWriteLocker lock(&_addLock); while (!_laserPointersToAdd.isEmpty()) { - QPair> laserPointerToAdd = _laserPointersToAdd.dequeue(); + QPair> laserPointerToAdd = _laserPointersToAdd.dequeue(); _laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second; _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); } @@ -89,14 +90,14 @@ void LaserPointerManager::update() { { QWriteLocker lock(&_removeLock); while (!_laserPointersToRemove.isEmpty()) { - unsigned int uid = _laserPointersToRemove.dequeue(); + QUuid uid = _laserPointersToRemove.dequeue(); _laserPointers.remove(uid); _laserPointerLocks.remove(uid); } } } -void LaserPointerManager::setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { +void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -104,7 +105,7 @@ void LaserPointerManager::setIgnoreEntities(unsigned int uid, const QScriptValue } } -void LaserPointerManager::setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { +void LaserPointerManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -112,7 +113,7 @@ void LaserPointerManager::setIncludeEntities(unsigned int uid, const QScriptValu } } -void LaserPointerManager::setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { +void LaserPointerManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -120,7 +121,7 @@ void LaserPointerManager::setIgnoreOverlays(unsigned int uid, const QScriptValue } } -void LaserPointerManager::setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { +void LaserPointerManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -128,7 +129,7 @@ void LaserPointerManager::setIncludeOverlays(unsigned int uid, const QScriptValu } } -void LaserPointerManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { +void LaserPointerManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); @@ -136,7 +137,7 @@ void LaserPointerManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& } } -void LaserPointerManager::setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { +void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { QWriteLocker laserLock(_laserPointerLocks[uid].get()); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index ff63927be2..b239fc1514 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -25,32 +25,31 @@ class LaserPointerManager : public Dependency { SINGLETON_DEPENDENCY public: - unsigned int createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, + QUuid createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - void removeLaserPointer(const unsigned int uid); - void enableLaserPointer(const unsigned int uid); - void disableLaserPointer(const unsigned int uid); - void setRenderState(unsigned int uid, const QString& renderState); - void editRenderState(unsigned int uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); - const RayPickResult getPrevRayPickResult(const unsigned int uid); + void removeLaserPointer(const QUuid uid); + void enableLaserPointer(const QUuid uid); + void disableLaserPointer(const QUuid uid); + void setRenderState(QUuid uid, const QString& renderState); + void editRenderState(QUuid uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); + const RayPickResult getPrevRayPickResult(const QUuid uid); - void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities); - void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities); - void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays); - void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays); - void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars); - void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars); + void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); + void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities); + void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays); + void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays); + void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars); + void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars); void update(); private: - QHash> _laserPointers; - QHash> _laserPointerLocks; - unsigned int _nextUID{ 1 }; // 0 is invalid + QHash> _laserPointers; + QHash> _laserPointerLocks; QReadWriteLock _addLock; - QQueue>> _laserPointersToAdd; + QQueue>> _laserPointersToAdd; QReadWriteLock _removeLock; - QQueue _laserPointersToRemove; + QQueue _laserPointersToRemove; QReadWriteLock _containsLock; }; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index e1dc1f35c1..7cae7ccdc4 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -17,7 +17,7 @@ #include "Application.h" -uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { +QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { QVariantMap propertyMap = properties.toMap(); bool faceAvatar = false; @@ -57,7 +57,7 @@ uint32_t LaserPointerScriptingInterface::createLaserPointer(const QVariant& prop return DependencyManager::get()->createLaserPointer(propertyMap, renderStates, faceAvatar, centerEndY, lockEnd, enabled); } -void LaserPointerScriptingInterface::editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) { +void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& renderState, const QVariant& properties) { QVariantMap propMap = properties.toMap(); QVariant startProps; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index d4297c59ac..a6b61446a7 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -22,20 +22,20 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public slots: - Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties); - Q_INVOKABLE void enableLaserPointer(unsigned int uid) { DependencyManager::get()->enableLaserPointer(uid); } - Q_INVOKABLE void disableLaserPointer(unsigned int uid) { DependencyManager::get()->disableLaserPointer(uid); } - Q_INVOKABLE void removeLaserPointer(unsigned int uid) { DependencyManager::get()->removeLaserPointer(uid); } - Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties); - Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) { DependencyManager::get()->setRenderState(uid, renderState); } - Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return DependencyManager::get()->getPrevRayPickResult(uid); } + Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties); + Q_INVOKABLE void enableLaserPointer(QUuid uid) { DependencyManager::get()->enableLaserPointer(uid); } + Q_INVOKABLE void disableLaserPointer(QUuid uid) { DependencyManager::get()->disableLaserPointer(uid); } + Q_INVOKABLE void removeLaserPointer(QUuid uid) { DependencyManager::get()->removeLaserPointer(uid); } + Q_INVOKABLE void editRenderState(QUuid uid, const QString& renderState, const QVariant& properties); + Q_INVOKABLE void setRenderState(QUuid uid, const QString& renderState) { DependencyManager::get()->setRenderState(uid, renderState); } + Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return DependencyManager::get()->getPrevRayPickResult(uid); } - Q_INVOKABLE void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(uid, ignoreEntities); } - Q_INVOKABLE void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(uid, includeEntities); } - Q_INVOKABLE void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(uid, ignoreOverlays); } - Q_INVOKABLE void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(uid, includeOverlays); } - Q_INVOKABLE void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(uid, ignoreAvatars); } - Q_INVOKABLE void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(uid, includeAvatars); } + Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(uid, ignoreEntities); } + Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(uid, includeEntities); } + Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(uid, ignoreOverlays); } + Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(uid, includeOverlays); } + Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(uid, ignoreAvatars); } + Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(uid, includeAvatars); } private: const RenderState buildRenderState(const QVariantMap & propMap); diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 1ccc27f76d..0814466e4b 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -125,7 +125,7 @@ void RayPickManager::update() { { QWriteLocker lock(&_addLock); while (!_rayPicksToAdd.isEmpty()) { - QPair> rayPickToAdd = _rayPicksToAdd.dequeue(); + QPair> rayPickToAdd = _rayPicksToAdd.dequeue(); _rayPicks[rayPickToAdd.first] = rayPickToAdd.second; _rayPickLocks[rayPickToAdd.first] = std::make_shared(); } @@ -134,14 +134,14 @@ void RayPickManager::update() { { QWriteLocker lock(&_removeLock); while (!_rayPicksToRemove.isEmpty()) { - unsigned int uid = _rayPicksToRemove.dequeue(); + QUuid uid = _rayPicksToRemove.dequeue(); _rayPicks.remove(uid); _rayPickLocks.remove(uid); } } } -unsigned int RayPickManager::createRayPick(const QVariantMap& rayProps) { +QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { bool enabled = false; if (rayProps["enabled"].isValid()) { enabled = rayProps["enabled"].toBool(); @@ -173,12 +173,14 @@ unsigned int RayPickManager::createRayPick(const QVariantMap& rayProps) { } QWriteLocker lock(&_addLock); - _rayPicksToAdd.enqueue(QPair>(_nextUID, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); - return _nextUID++; + QUuid id = QUuid::createUuid(); + _rayPicksToAdd.enqueue(QPair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); + return id; } else { QWriteLocker lock(&_addLock); - _rayPicksToAdd.enqueue(QPair>(_nextUID, std::make_shared(filter, maxDistance, enabled))); - return _nextUID++; + QUuid id = QUuid::createUuid(); + _rayPicksToAdd.enqueue(QPair>(id, std::make_shared(filter, maxDistance, enabled))); + return id; } } else if (rayProps["position"].isValid()) { glm::vec3 position = vec3FromVariant(rayProps["position"]); @@ -189,19 +191,20 @@ unsigned int RayPickManager::createRayPick(const QVariantMap& rayProps) { } QWriteLocker lock(&_addLock); - _rayPicksToAdd.enqueue(QPair>(_nextUID, std::make_shared(position, direction, filter, maxDistance, enabled))); - return _nextUID++; + QUuid id = QUuid::createUuid(); + _rayPicksToAdd.enqueue(QPair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); + return id; } return 0; } -void RayPickManager::removeRayPick(const unsigned int uid) { +void RayPickManager::removeRayPick(const QUuid uid) { QWriteLocker lock(&_removeLock); _rayPicksToRemove.enqueue(uid); } -void RayPickManager::enableRayPick(const unsigned int uid) { +void RayPickManager::enableRayPick(const QUuid uid) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker rayPickLock(_rayPickLocks[uid].get()); @@ -209,7 +212,7 @@ void RayPickManager::enableRayPick(const unsigned int uid) { } } -void RayPickManager::disableRayPick(const unsigned int uid) { +void RayPickManager::disableRayPick(const QUuid uid) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker rayPickLock(_rayPickLocks[uid].get()); @@ -217,7 +220,7 @@ void RayPickManager::disableRayPick(const unsigned int uid) { } } -const PickRay RayPickManager::getPickRay(const unsigned int uid) { +const PickRay RayPickManager::getPickRay(const QUuid uid) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { bool valid; @@ -229,7 +232,7 @@ const PickRay RayPickManager::getPickRay(const unsigned int uid) { return PickRay(); } -const RayPickResult RayPickManager::getPrevRayPickResult(const unsigned int uid) { +const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QReadLocker lock(_rayPickLocks[uid].get()); @@ -238,7 +241,7 @@ const RayPickResult RayPickManager::getPrevRayPickResult(const unsigned int uid) return RayPickResult(); } -void RayPickManager::setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities) { +void RayPickManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker lock(_rayPickLocks[uid].get()); @@ -246,7 +249,7 @@ void RayPickManager::setIgnoreEntities(unsigned int uid, const QScriptValue& ign } } -void RayPickManager::setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities) { +void RayPickManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker lock(_rayPickLocks[uid].get()); @@ -254,7 +257,7 @@ void RayPickManager::setIncludeEntities(unsigned int uid, const QScriptValue& in } } -void RayPickManager::setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays) { +void RayPickManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker lock(_rayPickLocks[uid].get()); @@ -262,7 +265,7 @@ void RayPickManager::setIgnoreOverlays(unsigned int uid, const QScriptValue& ign } } -void RayPickManager::setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays) { +void RayPickManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker lock(_rayPickLocks[uid].get()); @@ -270,7 +273,7 @@ void RayPickManager::setIncludeOverlays(unsigned int uid, const QScriptValue& in } } -void RayPickManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars) { +void RayPickManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker lock(_rayPickLocks[uid].get()); @@ -278,7 +281,7 @@ void RayPickManager::setIgnoreAvatars(unsigned int uid, const QScriptValue& igno } } -void RayPickManager::setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars) { +void RayPickManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { QWriteLocker lock(_rayPickLocks[uid].get()); diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 47d982494f..27428ab43c 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -58,30 +58,29 @@ class RayPickManager : public QObject, public Dependency { public: void update(); - const PickRay getPickRay(const unsigned int uid); + const PickRay getPickRay(const QUuid uid); public slots: - Q_INVOKABLE unsigned int createRayPick(const QVariantMap& rayProps); - Q_INVOKABLE void removeRayPick(const unsigned int uid); - Q_INVOKABLE void enableRayPick(const unsigned int uid); - Q_INVOKABLE void disableRayPick(const unsigned int uid); - Q_INVOKABLE const RayPickResult getPrevRayPickResult(const unsigned int uid); + Q_INVOKABLE QUuid createRayPick(const QVariantMap& rayProps); + Q_INVOKABLE void removeRayPick(const QUuid uid); + Q_INVOKABLE void enableRayPick(const QUuid uid); + Q_INVOKABLE void disableRayPick(const QUuid uid); + Q_INVOKABLE const RayPickResult getPrevRayPickResult(const QUuid uid); - Q_INVOKABLE void setIgnoreEntities(unsigned int uid, const QScriptValue& ignoreEntities); - Q_INVOKABLE void setIncludeEntities(unsigned int uid, const QScriptValue& includeEntities); - Q_INVOKABLE void setIgnoreOverlays(unsigned int uid, const QScriptValue& ignoreOverlays); - Q_INVOKABLE void setIncludeOverlays(unsigned int uid, const QScriptValue& includeOverlays); - Q_INVOKABLE void setIgnoreAvatars(unsigned int uid, const QScriptValue& ignoreAvatars); - Q_INVOKABLE void setIncludeAvatars(unsigned int uid, const QScriptValue& includeAvatars); + Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities); + Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays); + Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays); + Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars); + Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars); private: - QHash> _rayPicks; - QHash> _rayPickLocks; - unsigned int _nextUID { 1 }; // 0 is invalid + QHash> _rayPicks; + QHash> _rayPickLocks; QReadWriteLock _addLock; - QQueue>> _rayPicksToAdd; + QQueue>> _rayPicksToAdd; QReadWriteLock _removeLock; - QQueue _rayPicksToRemove; + QQueue _rayPicksToRemove; QReadWriteLock _containsLock; typedef QHash, QHash> RayPickCache; From 6e78238f588684da0ffe3a7f1a32d86bbec35bb1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 25 Jul 2017 15:48:41 -0700 Subject: [PATCH 32/95] warning --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index db7c0e4f65..9b3fe10c55 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -629,7 +629,7 @@ void OpenGLDisplayPlugin::compositeLayers() { // Clear the depth framebuffer after drawing the scene so that the HUD elements can depth test against each other render([&](gpu::Batch& batch) { batch.setFramebuffer(_compositeFramebuffer); - batch.clearDepthFramebuffer(UINT32_MAX); + batch.clearDepthFramebuffer((float) UINT32_MAX); }); #ifdef HIFI_ENABLE_NSIGHT_DEBUG @@ -658,7 +658,7 @@ void OpenGLDisplayPlugin::compositeLayers() { // Clear the depth buffer again and draw the pointer last so it's on top of everything render([&](gpu::Batch& batch) { batch.setFramebuffer(_compositeFramebuffer); - batch.clearDepthFramebuffer(UINT32_MAX); + batch.clearDepthFramebuffer((float) UINT32_MAX); }); auto compositorHelper = DependencyManager::get(); From adda4f0598e6b7a916ab5ee14a6fbdb703c1a52d Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 25 Jul 2017 18:36:39 -0700 Subject: [PATCH 33/95] Added Blocks to marketplace window --- scripts/system/html/img/blocks-tile.png | Bin 0 -> 35130 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 scripts/system/html/img/blocks-tile.png diff --git a/scripts/system/html/img/blocks-tile.png b/scripts/system/html/img/blocks-tile.png new file mode 100644 index 0000000000000000000000000000000000000000..49de535c1c2e908165b7902e562daef419cbc4a2 GIT binary patch literal 35130 zcmYhBV^k#!)TmF^WKVWYw(I03W3p}6WV=qbZB3qRHyJ0}w(G9<`|i5y{@DA+{=c8~ zY(y$4NFgJBM+5)>$UmjURR91800008fQJMC05;2{dH?_b!bL?&6i_=wcmeMIHY$Y7ytl(;3%!-0sx>4{1*@-4&|l*K*aP5gis9B17OaJ z!C78pLy!TKy$aYmdWDrqJXt(Wt>1s50ir3FZMm|#S4`dK_b~Wl8(S8=9a42N8!LW$ zT}5Kzer{#(K5g$}6jSoQ_~zx#dLHI@U-GtgvRfSL12~)$y>AoKaCp?Qcr^C;(+-Lm zrsTEKvt$yJT1aW!j6}@coqoz2t1wa0(Z#Kr+G{DwQF}v2QLY(@s-WPTjqG>Qhbt9R z!3%zuj1@T(2s))Me43m2-2~}If^WUfq;8pYR$1C2BA8~U!aq1#Dn!QdX0kP!aJ?h( zpg746+D9g+_1>j_`$i$egy2r&)x^!+jI13O!r)xfP7nSxAMagErsbmV})xcoqXG&PrEG!o${+{tOC*wM>xVCyQbY*P$ zu(Wp6jj66q=bV%v{M6!s%vf91#wL)HJ}dz~?ivS7?MD^38DNA} za$>JYh`3;0^v9zB<9gBBH-BU;4CMgEW62REr_F-Bt`W*wL|vF@DQzRIwIW^93CEuu z@NWAo^^&E-tAZRntT82{|E(NDKjbv#Os&wx zu2j&aoSc-L)b4^NPv=w|w7s-Mjd94sC*>1I2^Ry!lPzf}OS5WFl4+eiE%niZvchCz+u8F9cvWs1tqFk)keWhf2be*Gg z$IhGaGGd1eX$HYQs|pC)6hQv3uEMqa6TnywlZ8#DOE)@z(YHbdS2&HlVkZj<&Sj9sCllMXyA<+Ug+ zOY6`ru{s&@oQhhx0;?}I^GrDoj+jwWO64vq_{AJ^h@+d^c-xjghUN^dFQfdNjc0If zd$_DGsJTlKO|%>(D#xC{?j5~M3)MCjrPte}%ohLrva=>28FIl-p8fjOw!>^dB5!uamN>VT%MEg~)7UUglePf5 zAuOn408h4mi7nbH!V{nkF_-OD;TSNA z2*^m;{h{Du1XC`jFvWbS+4H(TRH8_zU;p%+$*$PyyN^j{=7Kz6L}|7gd)qe_16p^x z>rTuM23~sNTcVUxAv#->Sni1%3&J9S*d)b{l^qi)GIXiaS7D1l8cdT=7`()o3Vuz{ z53y(jAz(wf48zk2l1R5}Zm#Cks+?8Whgj*rV@6GLXANr^`6w6a^0@E7H(*p1WeO4L zm~y;o$9868TIv<=U)$*&Getsu&uj2$u#|6C6dVrc#b0 zgS2sTguN(dY*>37ZK2|~3sqS-%tTH82>Z}>B6mttR_s|jrL#RF@xh9wG6^y7k21Fw zoubm_EHx6;3%0%m^w5LxvKEn=k@&GPu7V5l8C6o0uQ5A?T|pXQUFalKo}+#Ul{wjY zl?m1PC>7OGjmNGstEbHa?>NQ{7uS=d@U#n|_Rqn#TsUHvf0mMJXt;SpG?<(a`JQD) zX=3$aIDwf)O=GLV-&b2REzEN0VNE|O3%(f#RtAH&@Js~}Pis=kaWJ({jKgP58$^zw z|3NHL(}yr!Bg^?xN!?PHw)Bf;7S9a}7TI_8LSv5s855C@qdW}L}6Xcl!LvYkA!3G6o< zFDu-<<0jW|Xg$yDHtWv2e@_=2bf7YLJAXCMpw{sEU9K_OBYLdN;)O#1g0E$$35;BM#Td!{F47k<%>@E2HE4OK*3wS&HIK7k z6ke{RM3_es#v#xMXkP-Ayku;G)y*(weGALF-xEfut+v1m+O@x}XWPUU67cAz_(Hxo zENa-zO4(tAfLHyR8GEjiZl!9a?LXMqtL8Ce*Mx4iPobpL1w0*L3O_f4ZBR&T)}1tV zO4kTT-scj1Y1FTTI&a5yjpGxN_kRZzBWajFfjMq-N%3pZCACGs1s|$DrmD8kC3%VNOw$ zm0DQ~;KjN+un$4OY&?;+oc!^|!R;` z?N;;P_GXhRjh=2V&eeM4Gyg`vfu2b>6C%7LSiVXl+CXKSP-N}Iz#B9^5f@Q^Ik&`y55!HyigYbg%@d{i6NMuN(@bWUQXa&|7~Vv1Id3P+XObiLbK zY%RD8)l=99;A+tPHdE;>iYCarFd!JcD;XUVo_?~ zA8k}DvYW)pN+cL9et)CHupsIFr>}g&Nm*`5l3|bRs;~eA^fjeLW|V~Se5bWMMYqHo z?w6n+9v(KIOh?k=8dKM`pmT^jeOw(^V|SeXP@hQnvqNHQ++8(VR9-P7)Ef zugqZ0LBEiVCZSD8L$C4cs~!VJevcqy_1Cda!IxNR?!NToMvdcbg$YUIj&#PM9HUcd z15`XPJm4cVcA@aTdK@%ap@qLVHTUAwx^?z(o4fdiS_5`5Jje}hz^eAS?XC13NfWLo zdB|qBIBnP)Nh20$`o=q#3niPk9=>Y$P{E#qDiF`vOiaYWU5dqOg+-vvFpe^cV+IPF z(-N8NSGuryY!Y>o7^GEt!bfe33DO3ftf@(^2IZO=e5|^dnAGY0b)335;h=pgdg@EO z^p-Wx)^9hqogc2> zKgN;8TF4m@%Z@-Uj3IviQQBQe5y{((tl&pknB}~P+vixS&ZB~qT>+EdK~WPS7^uw? zz+OX%Ii|R@PvP_|(`h2_ z^LC`ZzUOnFW=pT@)T@xWDbfnuoL6z^TF^L9EML;DT1?*lT7 z32M2^*}pH+dXO}|ZTrk4{AnxnZc-Kog~g+CJ4;=PMOk*hKaVIr2*K7+#okb6ejq0+ zlVMD0Hj>6&cJcgF`z6?fh_&^vE+k`@K2Mo=57zPY2uRYml~Z<7L^CP+@G z+Y%a-+D(7s7u-A!jJtRQLv^7BX)hwAM1W{35K%xq0!K+8oF7TUSZrm(S<9{{VX8=v z3l+jjqejkS%!%1?8OF=QwMW`j`zrPTqSHmm4iV#RLu&HV+Cr}Ba+Lrj%w=vK4+tu zZ`OdzLA#lGkM@LXe?=rd)T+oC;=;VN^2Mb?h=8m0XIz3EmG0^y&A*{?wGGIXs~tNn zJDPiF$yp27GF?{kHC=5&)rY8;P{>&e8m@KGqc5Z<)#=sWJnG#dfLML`eq4h)lQO@5 zz&V!g^JlBFu~o7)R3fqXL+$=QCaKHEhFwlD_$0|H)A{jV`3lUI0dV< zKlq8S6nPL|9{d2GP)8s+W!HK|OP}NX+u#TsSYmRf5yPm>-U2zvg;4X8*=TdY43mzb zDdpf{aUI!gK&S3a?x@gK1EEa>vQrxcwFZYk+#?H3l$-3rY{fK~@*73)8fmnzb(SVv zh<*Q9S&Ilpn1hcsK?u`~^zZ!{^7zC7q4=!xNt3Z5#P|fQgcLml5=XO?z=r$&xs06n z^pwP8lBdgprIE+FRj~!BPqBu#nOhpv8a}7?mtc|sa+VUims3?m<_&LC-YAII_jQQZ znZZjjn`wb8jjb4CQV0Y!%5H6w8u@C5aQon5@FQnka_ZQQhcc0z-$)oaTN=7z95Xvx zna_3iYrXLAxQ`+3$D_k#|8s)3ZB7$3%jo*|OZdb>LW!33WE}O*;nC zO_6@#<6@>g8W`N)!%nmEGaA@H!M&0&Qo{q(GFO*SSD-=!to}>LI-V@zVj9xCZpkq4 za9zv|?u0LAh)4~hd8!k1aaxiL@hmc5yM9elB>PH`09-@~!Y!Q(cE9(|?w>nTFr~x= z3_8nvUlq4&_*tF1H`L;AUa**LYi77a%35-L4SB@ zy@imUI9Ar;)@}SUqEPd@HF5`fnP^2p3Z;39und#2Z{ePt2cRBs4^n{|<9LJ<(Mkj@ zJo7HA3qSAQc42+?c`poBJ(5!JHGFrxnr$wdHj}FfMRnc$x~>eSNxj?{5pr}q$qlZ` z<@s}X9T}SUA>iA^L#7iO7krk2)%QCBXXf7dxPf{w?CY8w%o6`-%5X0Ro$;(3%9R|K6O1$ zne{_mCbC!$ZuG4BnoJlljKt)Q-j?wTBj5X2vJaLwnhu|};`PfF?Sat%I{M!vE3S_!L&L58aEJCtwY+YA_%cS7&@(Dp zoyJ?U*ffe}lhq@9#NmBbQR&79tubfy70e@63ID^XNo;CJ-lMTL`;SiHcgH?3eT_+v z^-hQsjCZ0X{MMgmsDZ6#egC$T=A$+JwRRudo6PzYb8!o9Qa>9-7W_KFK9n{n-hpA{ zE&cg5J=T$1P(-ZO7V{kzb;$YVYI(lZFAU`RqW?h^Ud9A$k-KvI8koh)+77FHq`rSt zm&eHLcAVuJplz;~G-)m5QK1NyjZ z{bqt6j!BP5|DL~mxQ~nnAoQ%?FKEUt-i@S0 z%-`x|ZSyj1xeiZfQTA60Pe95RdU?zeO6iRC^-`-qw})1DRl2aO)RAQykHdcQzm3Ii zOdwTD8+Dil)fc#8@sf*Gg-B~#Fl4<~L`FqLQtjZ~R4VXw7W=zsJqdq02bCqB)fj%s z#3PAL`xmV*i#>N2J`g#7u3#fvgOIOzcZUXz2XhW7jfkh-b}OO88-;nxC1Q(Y028H# z&#UD_ERO|b`nnx(%k*6r#h#otN{IWe7p=IWHV58$ksd+?HX&0pWOz{hgsuje{Lb?p zlhedsa-mGRt{fDv*dDeQWk?{dAM)8_=X*gT&n(P-hT6K&*=g8kBW^5lBh54@zO2-& z4xd9NNON)F>$^B!Z-cw3!nzSLJ{2-8Nr)jiw)8c zY6hyCLN}|OeJd$DH4OD4Jk#YWkCCio=U+@nJDrqwIV|CIQB8D?jw(GkP>3npr@2iM zTPKKm#m9Nc)gbg85I$ zAo93H`w_BowP}lYgYa_&PbpSkoYpcB-B-X=_E(@yf4Rsp7K1M-HE2c)7`KX1Yq)T0MKoX+!%#(omN2v=Q_Xmc4U@d#eArd!N?x>me=6<_moKsj7IlmBv&G zmt*4<`r3a5KU*`y5hc1{(DjNMjr0C@=uWEVC}(K#U01r6Y{OPHq4BRXykESrdKXs& zy;zMc8#ciLTX&Yav1n8A;E$l6pY^H)R)$kfYDvT-NDIG*tud49 zX-&&I20TfJ&LdNdv8d>&o>|*(bUR`ew7$7@P`{2}tJUw1EDb5sg|J^;GybZeAzkXWHe#4Pq2P0B+fJvi+UUdhJ zLuX*dFTIk&#v%NUeIE$y6CJ$u->leET2jgJTycj-0(u_fK58FQ9NG>1Y=^Io(3 z!3)nthr>NhTwRUgynse=@mOKV6Y3w9TUf|r{qg7IkR}h2ql4Gu|Lr|ALFgHHt0Un| zGt#UWx{_XA4=|+WK&h#9F?Gx?WVLdPQ&Zs5QK<=5!v4d06DA1&_TqoHPn$2fs!L zYI)!eqavuuqZvJHM$i)Wiq{-iwF~$XEX#*B|LGcGfp~hk1?#$dg#a(PPY-#mouBlL zk16C}x%l$a(4d+g8{Z2!dH*%Rvx8~19-ptKG?MJkRycV$%e&8twYM_jE0T^4|6}X- ziNeR_W0%=|*v!k!*YAY`^z`cQg&SXqt${07FUpN?(>QRwtar#uSjsdQm{Cbtk}&c` zF!V7jo>?2lG*b#0G|--UZ;7IJ1e8(RW?rH?u=izNd!~+V8>I@tDX6(CnAbRsb~fm91&K> z^Ht^xu5V@RHmkP-BkJe;k|ekrvfUymf1a*S2g-2#KhZxEJ;FTuEt|pHYGcCYw7=NU z;hsx%n$KbDy1@6}rKdYJa`US;x16V3jEM_BCky}&WnJ$xO+AIaj;mYAP#&LPCDBRixcRpj92>v60VLKdH_l~bI~XPubGQG{*Sos zv+8n_jmkl;<-zO!a#ptXg+1n84GnYWLB&zpIX~yyC2DeeM`RGz-u&(^yQU(`H;uru zfyTRTGsVj-kDHZEc3ce--ulDd$jy%tX%s@8t}pPZuhjB6e+w+)$q(HApg&PLMnkzp zqb^+8oyTo&TYup9-E|ue*HyQ>cmPN#&}Xp**XMu3zihL#tkNx*#s`&hekA%;cooEj zFOjFmKzl+jN|9n^^g~uG()ZdlL3-#zJZO2!uW##IF8hH%5!SkD51*^3&*Lr+%)%TW zb@1<~a@dba0z40Os0wN*0a)<#0H1s~6reqzPbGkJ=V~IY7p|CPJ0yHnSg#TO<}+L# z{@s561MLq<%_794s(R}>Dl?*5_-WcY{qPW?~su z3&ZWkNB3fQT&@4p^!B>1+Gl^e-lVBp<`i8mOwNc+@`xGtuk{8L_qkZ>|Tg{(*4AyokF=Nca3a zyvGxWciy6-IM&Uq)Y;O7gxgv6*SXj{0I}!ZWdegY6vW`vdIQWigAd`Si7)=WgK6?3 zh=(%FHxV!M9x9m111$Ijn$0f+A)tM)jVLZ#VVE$pZAm}CerE0Mc8*He#?Eh66}5H% z&Tn0`^XNJ*HJ=e?SDoG&r@p`wrW%b=Bnoo>-3kh7AT)GQ(#KpEYkJ0d2(}q?Rhj}; zMG{{m@TDxIE$`6Mt}+g8&r-+YP$%IT4-sm31qkebzyEn(4@EAUt`YFCrAW-4w@4!q zRPgu$N7h;QZqP{k>H5H+o2z zpLitJr&f$9HUzu4UW_%au&@8!y}5>P8(c*epKWRpq2jW{o}lLQrw_3YE>(zyu&jef z|M-E6@f;MM8syOa^(c5{fcozsJG@8;#*ZhU4U#1UN>d$>^g8L6Nc;;1`im5QmUE-$ z@^rggkr(wZlU3Xh1iZcxx^19y(2~5mG|mi4SzP+V9ID^UMjQN32vF*5xgtl?lv%Kb z5NDreqvo5Xi8yswlZl*Vb);jaWmnYtHcK*Rcr0BV*k6-3z!~Zk0j54L1P5X)R9Zu* zcY%AYs0s`x{YZQv=jBu=ikR4CFSap?iaA?l z72h8`e$)Y}mrt#euM$ILA_ajjBv@!f?a2irt6`xH-cpb16qmnF*cbD84qg-Q;-TQP znH+u4<=j}b=Y}BQ6H7+!-lm4rG70<^)<=0!8}qOUnrZ=mJDh`SYFccHkgbalb^xlN zXIn+pJ1`iG+w+{yPBkq(*PU0}Yt=G)8x!x}>I?K9?<&S&Oct6cg)2b{s=v$sfy^hn;XRgr=Cs;wZ8|b4-pUl5kW3k1E^NQfgVOOr8=dH*G0QH-Shd3%2zoaoJX(G z_y4H7@_S-bI-b_LGq6sucNVnsmPcupLt*4rz-lViY?lyGrViKU;7CmCc00W8`7PYw z{gHu`rI4fNzduUb<SF!&(}eK4JCZ+TX&t^|?i=ip>MN?o=R;C_WG;?!z^+)d6$?@y^H3VVD-& zdLE@mk%AK3a53ZN1EVqQ&OqPb@;s8fWD+R@DyLn(!^xZGueb0muiZ9I3#M9LN9TvY zf$|zfQ8s zZ}{$PWQ4uJe_Vve<$wl-O1E#fbXu;xb%GNFK*Z!3l`r{ zOpF4dlxpPS(k+Qdx%1(qeu*(}$;O3wP3vVhpHNqJCqC4u9hv9mW@iZvfM*2k%v$wf z!rJ|9@${frHt0^P$ax@(tO3|pT5-KS!kU7Qp>#d(G9PKec<(0RM`~N^!t-~2rQPwH z+R)KZO2v79;6JTY2S`qjx|{w~4b7Y3;U7NCT6krsMkC0>Fw$WH>%mW%gw`2^HoM)8*v^;+KB$FCGLo4*g=+mX`LFZs8L+ROeFaOU=WS)0mp zn*YY@M#f)$TJ$^aNj(?tJXwEvIAUh>d~m|6AJS5LpEHE{`fodIbf-gz|^TxQ$eWJmNr-LfSa4ahEx^h zQpm!5`_%xSYUse%YbwDa42eOKPwsL4S-5<~>}zXaa8-h78ka5?# zr2WbflJS}ZHOLUO14u@pgW36VkKydGEBD>%u$O<^Vjr$_ADr*_(bi$vOm2Zrka=Vo zYKgEaqljq@Nmu?9qy8Tb5r31QsvUhvN&NZKqoFjDbI^1NRt!Bz=Jzg?GF$a=Jn1k z``8lt`*|OVY>}t$@(isGQXBN6ODl0EO}J+6q&d9{0`jeXj7G%P2suO6?oL*K;$+j} z5b7h?b@k9~Mfv>cu{ID(ptPMqcoHnLdd-kUQHD+cRS$HJkHFh{=6(Iw@l5wz;kBE0 zhg#1^DcL+vr&$gE^@o1uR^NkO_a#PxyQyazsbG}%T?A{Gcv~qoNW{-M)hFkFlV5sW z=BqTsT)BS@34NwCAGw?WJ5kw(gYi>SO>yDIvvz})_;v#SNgT&iio9L$f0gI3(%7Kk zc8dEM*iIS}V06hg8bk5Db63aXXn|XqqJz)r%EJ*;i|_s3qO6yy?$G@&nu>T$;yfIw zt4g$6q;FDzA|wT}lE*cjzxRURi2q*Bv3Jo--_BDS3sk~<6askxV$Oh4ehFWU9|%}) zPb5Ry^*5tqG1ET2=8kY(QDx%rG=TaVSZ8DH4CpBMh146R;gJ;bj(-rfmGFKCeUofY+= zDUM!bH?r&8TA16OD26Y~Ky}%y-LC6k_c6`izL0w4?f>I|v`g|_I?4%OO-SUHBb1yi0>>;C^{>Hl?enm?6ljuk9QhOxY>a3t7k0{kfkJgUkG%-0hSJ z3GcNN%#SN`@W=08cVL9P4=$`%+&QeYJ8$jCA2HXKprQwE-4e^|qomg;88inRRs}qk9vfWR{N=H}L|`&m*Q?Fv{Ila|$y1VNHApUlF6W zdxVu@vf*;CD}tYxd>$C^`sT{TXHSf;3lMtZv%xOcBac{fz zYD0e&x7|EF-1+U=fx885eO{7po;~*x_J-49@#6?%cmO1g*_j7e9H7xbwD&)kvPxJd zq)Jb%y?ClRhT_y=UTOdR#Qlz-Z6DZI5(klo?Q~PuJe6v>`p0>{)DWe6S zRb@Oyy$<@x#CxIMjD#q0knne%ysLKMGBbJa`yXx0rE%2=xulMKb;mvBwgD9tP;>LA z#T~gygiQ7NDjKhzCol?<+=YwI<(_X?aR2F-XekQ;?P=xIGa-PhHReD(&Q%rVZ z1-QU-b=L5m4Y9c`)7mcmIW?#s97KiqG-!T>ffM<=RBZh|gdt5FHvC-)O1hEh`3YtUl@fii2@JmHZFjvPaAH**lWC?t@5{p402+%Qu za`1anDc866=^xxbY(VXyV-uVDMD2ACfy_0$PLJ*EN8GtQU5_lDq6-cAr_iHgo55vE z#QYsQ@AGHV0?j+;B@Z;r)esMAVNjd0=Vhqif`g+nG}%$y;WHSK_3hqzH>qh`o-feR zUEE(E`r~?rE|G}@;T8*|JC&A(c%q85Fdi5BWUltfW)V(p2I-D9qHTi2`zmrxAvhVd z;UfZrjvm`{q|j->7UR1WD5B}F$IK(Y&T}hjL8*@ezDKdXAVX1}fL;lMH#)Y$gg258 zzpKRh!xew~y05mf&p0=i$6C$V>w;;O_Af9Ud6(KY!ahJ3s=Omwo!*rRQ{*nW2CXJc z$yN!I)|gx8e+T40ZytCjK2%bWL$)l)zz4q;d7X!%Q3XJu-;W;)(L&O?YH??@9^SeQ!P=R<6K8PXl?H&fDPOMnwnFAlLnn$~aUq zaNfBfbRdji> ziXLDMXd7`3u4xAfQ3Mu>=N}s{7zd)Wt&q0X7g+fusjh9SDb~0JwwIAHiKgqX91i#K z9$T6J*7cDrOh740;NK{}9$sXg()GRr<&d0s+D?bL9M$o=JMGP~-(TP}KvHT#gOO4G zppKH0(gUOw5phxX0m)cnK|sHTujlrGvd!BC7rnUi3C)=agML@MpZNLRWCoK*jhv`n z0t-QR=p9Y0`J18GZwF|;kkT^0(B%vO`5x0zVa1>>rLUYiMvg~+`iE=oRc1f;e=f|m z`Nvbb+$pru#N^!~I|ii5DbrmGZ||rZW!(wy;Ga>Kak;--(-JjKzKy|YYS1Ym3d1Ds zr3JT&WG4fu>hrrH8yuiBiO7d7pB1xLA?=Fj_7;K7b!2(REZj3vUkl4SZE#((QPZHJ zo?j^>dFtj^%lLO*iM75`v%P}<@_he3jh>uM>90EOzPF2&fsvKS;)Sb)0@NdFkEiMl z{6Sb3JDhN_wSvxG8zs?#23~Bwv(!)}Sv&b8xxK{<$uHM|&gDx|(lcJvd$eBZyfaR?w>SNExA1%qQWLh z1Xvg~xt9dK1}>ww#=LexH#0_iMzu~9Ad8&sSz4s_3i9+^NC|^f+ELscnSuvrD?C9S zk%^KwDFwS=?d2d84W0*asUU11FQAnzTxF1H(SqEIfyf#QoT1jukX{8AUX+x-#ZlXFjBKuEWXkpJnzEK>z$I6EF+tN9b8v$$-@ zF{D$>H{R1aN=2T|%h9nITqd^*-sHA-*nv^`!3~+o7#A$c*|JGi2NXfaeU5K6XtM$> zqv)&oLVik1rgq;(aa0(Vg9?MfzH>?M~NK!v%E-H0S<8C)XN+ zM?HlmkPjj@JKRZr0>93s=yB+R)Q|&A zB&$Ld$z*yMu#j3^3yei^f=U(G5R!?S4-gA9|N8E!A}!#|l3Bz2$dvtY~U zJO72cs>D5FaZ{Fqw5zKo*~VXM?{r$}t`_I>=PZF{nOL~v^L(gTO7V$UpzX0Ya&v&D zj{j-0e`Dm<>nrpVlIbh(+ozu8!WM_0IKVCyVQ}AFPT9ifhZhVqW&JsQ>Q7R-M{@AD z7xeO|ZLer3L-YWs2m(XSXY0#Z2Up#9rgg*666!G7fDieyo{Yzo`C(kDBO~qLEy}_y zCC?zMS+sHCLinX&O_qje;4x%d46^)QR`x1votJeD(t;qP1dAYnN*sJi%4W6rZ!X6B zj<#}~<1=)$^Yr)>XvK)>C`INN`f6@#Z;ZOGTGws+uaCG|0l&xBvYxi{nK3$tj+C!Q zI~79T`tNs%$3`O}a)=WD_#qbBgUkt_3PYJ@yd)td@&Jj(dJvQ^WCdF=Q9-jPy$iU3 z_A)PHxTyjkzO``%;w5V?H~gx<^U6Y`=6n%O`>*gEv!RYrQn5yzaf;6xBf=IeAo0+V znl72*Yp1crx|mNe2O{LYG4n4|s!H`qBlqep!q%tPe4mh^gIBAH=sOnM_$xp46F8R` zah#iBXi7tgOLaKK_CrweXcdILOn|`a6c+5?=`G`<0`Zz9rkp#_C{9WO0)}{M7Um1V z25NINCZvWw=HMmDp-5~4;{046!F8Dtmnv_fuIO@%xP4nq#lUiih>uC{l0P)({=|HU zP=7_J=6tU|qsuKrKSZ6HW;ts&u>$w_2;bW4PjlMgTXd<;oTZ$plzuO_HDF7k+6S|i zwzw_5?klM%(JobRVnq`B+*T}FYC|jNLrZzZxd;4x20ahTQScIUO8Iv!62|E3^&!Vo z43%KvA!rh+jEN;8VI!%nTV_}iW-YJeAO=O5S!?ypDo)|QRk)vb zWWP9WTPSX)3V+8^gNlGsT1XQg{WZz;dDD2GO(SZis_Y8aq~65^kM6PF%cH0d>hQGi z@j?)+QlcqTq+KAf-T7^)swSqQMYVfGZfG8u@1DP;l&V4hS9#@vQ#U~X9`+` zy?|wF6@sLP9{5I4WM1ojILSwQ4w#d-YZi^CV}h7~D+@z-0TA`tX~#hl zcz5%viN0pe#`!^SZbJ)W&p?|ot)YPLog4MGJUy(zMTz$l;qZyOKM2BE;S zK?d5o2qub(y6Hz{^QsmTyW72b{b+iEo*XSspt?l!s=esjf`%S+v^`$z+m-)4)YTjO zm&`ZiajZpEr2IDAo1b`e8yr~mr>q4vjsM7xOq9=O&c8_;uV^qN0c%Vo|3Z8e6kj8& z`FAe_BpRN7fgz47XbBDH$iawYyMTx@jM>O7ZS+W(W*ULtb70@T=eiM0ZFS0RrWqYs zKGC(I)>B9)Nop*rxg^CU>!v=u4qcqgVQ$`LWc`N)ZQOEi1r=yj4OLs5_}&8>y}ul3wRdA(F7^t-Q2zzFX-4Qh45E>IzkbcZovNJ4ki7n=sfT53}RmA zHaTCrtWWEl{JcRibk_4Afsuz(q7M*wL62I)a|j+e7R%57gp%6hwu^O_i{#EmIE+aO z-oIOncMUszW{iK815g+TE^WZ99%d4r`u@zrlQcE1q)h~~gb)+l!b6%p(ONz(=ujxhx(4JyC(5DFU`$0c z2)ZCm`}v`miEkB6k4fP6iMk^_SfNLxKq_+y*TT1mQjNsWOyS2FM67*oKEIzJNILrn z2r33|r!(Tl+s7aL&`RS^qz`Q1R~KN_HoD*Dvdr;%PblxJgO))=9O7#ZBcBac6l(r1 zAKlBX3#|&bQ+Qt9sx3L6lM*otnL-|pflMLDnT%4OA8{UZ*E9vW0qZ6kWyW;s$%$rH zD{_F=*4HjkA}quZ8fXTS-U+{ik{_vH#-xq%h}h3c`RFp$c%-uKEtJI4h_5WX8J`yw zNeDUsSHtm=aWMaqE617`0zug2v^B5Ngd{04UgvQ%BY&4P#`)?mGTfm(5oMN_p>J}$ zyq&=kEXftsDl}S9nNoVhrZv6*Dv|7)#fdW&mVE8UuZ|VKTZrEW2l6{qe)lfe!4=lD zB=qT{>|)W6hSB##2W4AasScMt4Y}V_%Imz4-8W+H+KOjEG- zzm`Y%F{ZjKv!7cs9xWerK8$wB!I}5MUh5vWoj1=z&#lOYIIrzR2fT6iBVtv`XG=m} zN&h_5&@Rk&JWM8YE$a{qyBM0jH``wXFKNzn+bw~p6f6?Z^B}odTE{kG)(u;v^4ru* zo$=7W*$@wkqeTI=5gEdbf}4siZ8su$h5%p!(xltEtS5rJrluMvjPa(+g=hCNqCoUUj+fgH@zhi!G@S}V zl(nYgP*trPAD`_o*hnDmWn(TCD=AjmjC`ujN6$(G6e}4mVEIKu_Z#O`R{uTbPqxPl zAM1qlBu64CJ|#k7@%J%0N$1LhWK&8Su{amgVH(Asa!m5SQwhdYLHpmDoRvM~eDR!> zn`U7Tq^X0=&8Ta_81`Yu5Go{`xMT6cyREWca-B58zbxTqI>S)~yyn2(W6$e>&m~t8 z+zrQTj0sw%NxZDNWPquO_q78^8P2U7_cs_-mBdg?O2#66F02!3iE@Ir1V5QxFDz;Q0Lx7Bdvvn1efp!!}XI2F(ttH5KWm73y{cQ0>c#9$CW}Q=8DLsMcy{xzed^ zFy@hPADdn8r4^Y%E3y|UhP$e-v2>faXuG>;ySH+iZ~m4p|K^^KzIOi|c2loRlec~-489J&l608;Rly8Wbu{jA;Mo3OElAJ~&B*ln##wWTG5;7AK5uUM2 zeqwTAQesuAW3J0tljUg4OKmGkSz4C1yfUqKYWmw}x!yfD?e@C#?G3Jw+cnhW8u4Y_ z*_w4%Yu2ugjJw)0?rF`ur#1WTmh7D^Svy*?A*0P%!!6mv%~?ZDS>YzMnPG2g&=Wu4 zN!m5lwJFh=XCxw*kk23?qM#K~*J5Ibt7e1N4t5y5JAbX&NT=6T4U6Lbdyj$o_$Ys0 zEK&p`-9K&YekyMCV+j@YMEy8bjA@w!LKmo8Emo*I+j`oJR^_q~xT0_d!}!0^WM?v-@2f4TU*Ob6_u?< zLKc!Dj?JL8({MP9#8fj{Ly%{~6LJ!h3!IK}r=v18WoA~2H#fyU#o1GmvSMo5`srz# zW~IHoHf{6#w7y2yKx5``6S$jsPfO;VzO0?T%w4Tnclt7R`7*%fJ0ZTD9nG1eUUbVE zYR(EbXAb$YhP+u}Z*I_=HQ1CD^5g{FSwThgY-T*@jt-^*i#I)7pV(iQ*grq1-;*4y z&m7FlXu&C%kGzPTa07i^1e&@Ps@4KY#D%nPh=P^}j6m6i9$Xr!35F|v>A%E1e#toZ z19Ag6z@z*{mXAFaU%!w($f=(0NA8x0^&kbBmMe$QZIJp*03%|7*4^I>Bz}+-IXve1PyZu?9_zu4d`N@u^tkI@S2xtvXgUX?Zl1Z&;fdV!YY@)5;`j9ts zM2zMxLF}Rw5;y?4geNUjpBQLJ?5j`Q=1%JOCJr>FkItTQgEMWGk>Fsbr5{`|uhBn4 zY$NB{Ygg0P(tYGwtn8Eqy4KU&IU1hQx-JtHHSqhTDfW6^Ls z2I>XZ823H^f3R8RcPyW%s-sYo!X&m&x>{u5{(jEIKXcqLHFc&IE_GqsW{I}$D9;T2s3 zmNzza6f`_J{l4Nr+w@>Z{osP8z_sKLfopmKi@OJ|>FK)$F44W6T%tR8jeoeuJ={Kf z#9uz*%?o=oL!Qi#nu3FUD@yQtp zj(q;Z@pMrnX5dot)r<|rVqQcIBVvPEEW78?3tj#&4-c;Hhq+AKA@68|7%d7y5wQ$H ziV4M{+sUDAE*p$FwLqnaL_^(8D>0#UuP7MvNXB;)u}y8lNPmHb#~Er&4!KjpjZjiU z-t17*lyKYh(T;iH9#3dtd;j7tc*4Ln3*ZdYUb}GM+OF`m?K>7W4fo6&?JPmQKH^Ou zZcZO+P6s353?shGQ6JU^Z4pJX?p{ff~0}QxM00wps_qyUHq0r=QR4;w^4t6LtosO(0Vl?`dUv2 zE&iaP9!Cvs>ax3PwK545vFb5JchI{}4z2cypomo;53Qnizba_8YbavX$HVcWJMaak z1lVXw3wR-^0Z;0HJ9VHTHPGN3tak>GD%3d#8(pEs+>pO~v~BiKSAB4iKZI(5lBEUx z*De~kcJaWq3j<4gMy_ca?U}!`W9rV9Dag);z3Dre(nnfcBP|&tNLr91i6*zlwbdQyTAFDZlWw4gg}(33XkP7RTyglJ`Ogx$%( z#*|P)ddQm-YAy@4&I)zagcr38p@2r&uo#|jP5-h*!R0-n&Vm&C*^!1?(uV62O!g!E zTRcG^%Rpm1l?U$Z?e&%YbINaWrPjuwI8LC?c=KI(^I{uka%lA^^Hy0_c^ib7aDs9$ z(o^-n3VD-L$A(uVS9}q!c4~qw`9^YnqLF17NeS+24DjBYI_QN1qz<~t0a&1m1EdDg zdQz0QQ-bKz=m<3?g&G{826W2`G#3u~t43Pq1v;7s7Pf~M_k@=&4zIXoWW}PLOWJoV zZras3XVhP|qbX+;ZqSrI+>$=Rxjt&*krooF0Vs;2ir|z6JdUJ8%xp_u6b;Fupx3k@ zBWiRE)+Zp$4>YhFpj84l(0T$rA#F_PYlt7LcWr4X-&{9!TUFtvq{Py=_%wP`L6;j> zOmyzbf$@!35i+g58m(_o}485_I57)7=0rDQs5O$tt4_J$`TW584s0Z@{7Q7^;2UJ zh)buxXi->K`QDE#JAKjc5WfSw4lwW21{;+Rhy$3CrWLqE*pnJYi#5TG^}!i#Ob%j+ z@Fov>(?Tsd!~TkJ$E=~A#^Gz)hL?7Smn|AvcFoYr1-q8}?_OB9(?4~{TQK6z3S&%f z`cO*-)d1uJER@izbpVRkO{ltAA#{NvR0Kmf-VfBrL;4!xK=D2(B%&uoAXyS&9H?_{ zuPfZzSb1x0)g47yUG(E$2^sv#50{UGFK#5F2-Gq;)S}~)+)joR$%tp9tNWy(xoStj zc!IJ!Lvx(Cq%3}ko|L}In!{Y@=Hv41q2t$FcLE{EdNa)nvq(X znvP9c^N_3uCPEg=Wf7QX-F@6eklodo_KQFYTInBU7m0>6R9svp{n~zJb?&yEi;taH zcjUy{y@w5V#!z!ws3|QB@uCPOmLtpuJ!v8M1{e=T96-U;AlUCogAb5J32j9c5%4+( zJ&vF!dC-%DcF3DL?8zBuDjw{ZF|wcm{t#ZaU}WXu;Z+NFt!Uf1#68kEb;v(u7-fSe zJ=By=udbTXhv@xRx~m0}aaT+Foh|7*o6<+UX(Nb$wW(X?q~10?<@&0W z6%~#p1t~qbj+RVEU3&5yXHs=iQenI!+epkX65tqcHYcwt{9-gYJuWFdK8b!Vgnr^O zInThs<9z8SbLbD|@`>QY`I7|Z=Ls|v!3px3qpp(eBH&&?5fS4AQ0<7J5)JyxT}Dbp z?mI$jPhZ;n)vw=r;o^-KFWqwCS;Lb)tFp@_xdvL_PKU~?)3P9 zt_fc*zC2`W8u7bEd}uR9S?GPG-?ghbp z)NPUr7>}qQZ)B7e-!yp5!4q#ge__j|=eAvZX3M2#H(z@8_NSjQT8nprrnm$x86z#O zA(mmd0g@9i+YMogvjZ?REm~xgQkeSi0jv_do&cK8K&5uT;|O_?FC`5&CJrKNa;FEq zdBeWSK-awRqUO zM8RIFUQTtGAmB_jw3Zb;9j z44MUfd>QB|3k%wvzRWxQnRm9i?ru-Nr_FV5o9iBb`dwJk-LAogwEo)E+vcX;G|TzU zsg89Oj%7uTp8RBQW^zq>@(gEEr8B84DXAb4o{+#Fg-nE>bKaHgic5B3NuhFu60nST zM^=I}J25#oNiklop7lyn(UKgW&(xnzo87Woq0 z3<+Z)x|f{)Kyf>%@Z~pOT<=;VJ<@$Dc_B=9fpL9xaecFmJ7yc3MP?dz%rI`BW86L? z^^O@+-aWhIrrOGF(~91ao?2nVr|^gW=o0fEut}va)2VOe)77V>R^0QIWb~w(I7`%%I1$vn68`alI*R7+Gaw(oj=6y=eDk zj=4mzKn2-Fq@)-nM_6?t{b;{D-)eK%??0IJl#Nx!HDRJ~kVP{+df6h|M9?HRRG3B$E$azu= zZVWHodveqHv+ItYTyyAn@4*wBjvU{1>FKRR{inBFpw@8w>wlMR{dg;`DIG2r0dfPh z&Flk|jqp;Sr7i|<a5?{Gvlt-(&6S@tO-F6N?z-u(#-IDM_(NRe?nhfqJ(x~ zywb-P!F9%VPx8PG-5-5h>xV?%+WNt_w0_|2{tvy?_kp#||JqQxr9Ax|vx;sc-HA2$2J1CMQ;AB-IwA zHdmyrnwk1`r0m{|oh_Mn`!nwIXWY|@^c}&~HHy1{Q^Q4GTy@X87yZ|bi~f6I`91Db zcsu1S(h7qGQsl;^pzINf*iB)`yTpPPV@!+cIXRq6_-N@)!2{`-0h`n5fJtG#HD%y@ z;UVx7xcx34C1B(yekFHPxstKdoiW;w0pucM-`TVx8Key#;&usnbvqtJY zpLA^dU~^KxFMX7}nHK^0faO9cHy}?)SCJmnL`$R>mcuu+11Od&-OZ3fzDkEU_D=#W zy2lBj2Tkw?ZxUH>`Fw?;j;fK)={vh-+}&Qe%U3kok~d19jid56Fh6M<9H5Rr1gauE zhkOwQr3hv?&)BlCY}eSt|6cyf-yi4vG>rsmx^zkKVQvO98JZo@FnoINicTv=Ed zbZSJa0e$U(;t)a8qt;`>W;hb2$RxqS(&8dNX>;Axl6e<$LVxDHNW)OQw4sv8+vzRZ z*aX6M^snD4@Hl5ZDvQ2S9ys29E0-+9lo-`^6JXJBR#e2qzIp7KX43bUW$I zgN#F4oxw(Dus%7^kQ!=84K`*3n{tO*@`qb;hnwL5$bS;I*T!#09qrv@{lO(i~Kxj$ft>~6E>`fW=I)}W;VUom!BWpaoNsOUSYyNfEQ(vI3BdD}qJ9P*pcM25E_apO77u)}RNKKu)kBbz5Eh_C{l%F>Zi7fkM7wzr_bgu{ywW zr@z1J-4DNK^Os5P`0{Gyw`J>{lZB{$6}ySX~&o#)T|AB=y0 z<(1;h`rJfc1uE3k8|J5P^{0=vrQg$@cCXKM7cJ=Yz;T$~_hlk((S@ZLj|jZ<)nzh2Y9KNV;jU!H7=WQllv-_6eYp%N>d8 z#uoe3HmLQ>9f^`Fy$B>BIKXFCyRdooww9?|yd|NAoSh!@NWD-nX zH_kP-K7am2>F^)-?4Itttue1}j^mDtC%y~ItFOGasNmmP((dwS+~q@Pca6#gv56&y zDTu32A&P^Mk@l~jjbC_UUe2PHIosVcZ}ZOH?47x}siM!DKiHHR@}`eAr|+Ow z1hlhEZ@7xeWG2ImY z11#`2ayho6!=T48NN*Afg8uTs=HkA_tiD>uw)qL$>y7?;g9=|rJ-2g>E!{<>1?3O{{js4QCMM>zneKx~hWh}O!@6ml~x)Or@%?X%y_ z@uCN}%@q?)Dpx(VP2R-R;pX%(VtP~BsK+(p$r@_TANE%aw@wcm&i8*dzI|hMiq}2k zj>Z{V+_Ua*&xYLQnSFcH)WPPGpeHBbmIv?@x2y*(I<4%i6QpGYHybxHmD3Uq`N-O} zXf}hXjo6gZ?@k#&@e0;9k^~!^fyNXF>5ZiKH&BN`cWMCAm@>c}`nfav5<-4jzb7pK zX-XgTrVlo|f>_#`(t}OuA^5Pbw7-37xV37yY08j0a{wLaD+<}eE!jgY*ku#du|nv3Fkyf0kUs|!Zp{m|nz(nCgAhOxD~0y5fDIoeY(+Fd!?U9qFRWN1y}dxcng9=z0)GuTx&(p@^- zRWjO9INF*!ijt$NXxE>9|5tQ)>D#}YXAI!nK}T5uOa~xWf#6!tHu^SsKm6c-oc`w1 zKl=HPfA`auetYTU_dmAtz=E>7K}T5-I$^fi0^(yZ4LFe(!~!|MDk)c>g~AF--w!6mMcdv4|o^J~`A96OJF*YOz7F#Do(} z&C4Bqt_Ni*I952~FCA^0I@C5N+%_-dpC9zq1Y75YTILP5%p35{4fy5^7|m74dA7M{ zZ*2hY$pN;yXKwY(+~Q${WY$*CtSya5jb?B2O$)YH4!4)>>?*ypt7Jz{*^cf~mNM4M zb}X>S!t$L9Dt0Wa7+Fv`f_7o$$fC-jMU~-&)DA7I99>v3y0CoL!it@s?80*N=guH# z`HltH7cGceCJG6rfG`BPhk78Spbs;i*$=w+&|ah11nCAWhd$cPkc6Sq%SJj1!@c$I z5n}DW|6)@{e^<$HcL^L|xVv<;t9VCk!nRMn_po$$@MEXu7@NHr$cwgvSg^eM%B$`9 zyHJJW9w6c(06+3y=cKdk-|MfxzT;hw%rv%9LSniB0&`p5&Sy@4Uv-N9_pRrC(p`KP zmId^TPJtptFq~?m`$KmwmMwLGST`Sh?mGw99h|?dX^t z?x+cM)`Z(?5bQ&KIKZ5sZ%)uZH`FqF&^J5KGH0-5cEG4Dzu7%&8}WYj)<&i~Rsd!{ z`vZ$-_SUAk+kLg${dFX5wSi77A~VB1)u1w>Ecmno#0A9{09Fn!`>` z2;0I@=Atli80@4$h^(NsKyxcdJPvZt;hr)GFBSBa;v``y;N?EH-F$fG6+2 z=yCOR6oosBhR|ZuvRQY2>U{@g>&t)nJG_Fn79;N(c8f}{!YOft=uMM=#A8fCs35zN zAjV7VheAmaQlMtAzh=N++wZIGgZS(E{j~xA{DIb*K>NJGjv3*uslz>>JA44)98n)! zub{|HI-+~UC~uDJ-~aZ??|$>AKm7JDru_MpzpKdl-EaJ~x9+~y{2)0`>4-lk@bqaZf?r)!G3v`k z9@6)*o%^LT#u?anKQfc)#x{g}_{JySb3``b-#a=#j-ZY#1!4H96Eq0^{oq@_SY7k} z*~a$i#+F$|-;!zn`qc|B$)=NgUjWg^r$8{SsrmQ6{P}NU{M-jlz_n!9y$?Mj#*dEf zLrON?*b2ecd(BsApZwROs12fs70pYN&D0|33Y6%}?Szm;_O*%CXzL(Q8Ld+jMAXON zFmieW*pxHWR1ii9+dgBsW6sX@xx;Pq!=QWHym0&6aQnPq+nhk#+`+cF0Vv?Tk~xFK z_}K$Z>q#w_-X>a z`F;M{zLpv|KwsxZ0auua3(AHUl!X!9 zyDKPZ(G-Uda6D$BvrAYYDZ*On&rtSK3b&HssNEG*ePTdT)V#DW!}h}P+J=7>T1@iq z)9*XfnjazuVCS(oz-vop?CK~8ubO-B%YXg5bbd?A2j>`Du_$}f=?f3;l%c7{miKOd zLbg74{v|j7=zIH$Pm2Y0fm9EMUO&?tSVHhvI%!qV~TtFP^O;AzkrjE^|L^$%7W zn^({KcPvU``ON!{Bke&qFa{%k?WrG%-JM2D2a$EM^16*=&wXO2Db)gS-h*Ru8JKmP5?dH1vxgs`JOTRFfhufDcq`kmhNzJKde?0n=C zCmWrcF+R?sqj0z_f0VxU?+VQ{wtn{;Ka)PIYyN$zu?>~3KqTd$uO@*=U1D%k(?_nU zzHg4v=YdODR)DQ*KD)T`KJ9OxeD6_2eNU=9 z_p}K3BpsU1EiDcM>?eRojRO9DYt{A+ozb5=&=@bp?3r(`RQJx4Bcdo3hQF)`uMFi~o62 zI(+YipZRlxUByFDE5P(SJ!yTrA9zao+_>nYZTUfV0D2xpQo6IJWLHCS|9{@OPx^%4 z_TV&Q+pm81N9e!*&0l<3qo5`+AiDlTIjf&qT8rS1-*xC`Kl+{M-?;R{O5+Y>S<(%3 z2hlfrJ}g`D?{~lY)A1+2@xjpEe`){EmW&Z3LMYjJqRUjGS|1OuMD#AAa7*lmV$Nkc z13jJ}_N9-uXO8%$gj*|yyJn4a%^m5UKh%yGUpwf7)C{&z{2lbyg5{L$Fz>^y?tN6Bz!$q-8z(nW0uE5NNa zMYq&|_b3LSz!`Woa8KQiO4*O$<_;pSLilf<-v?+(8u*bB)dZBl0oYa0 zw#^@Co8R9yKhQcqfV#P3POy9WP&L7KzxI z;(F0Aw?^_POA%~=>;S3;*z>@p=BxqPDkGqCXHgh#aPH6x(r4s`2Yfk$+5xZvTsv)7 zbLPOgBUJvP9$hx$uCAgm4j6+k#F3YeETm#)M{7=Sz^zeMgas z=+3Xec-=>&q}DFh6~OlIwq>72)VFpma4kJ1|yvIy-V zKRW<|EXCP*1IV|r0#Jv!VgIaTTZY?b0?+?{Aqp&^)6LX_IeWppCeW zLmX(W;}&%1MSyq@H?=@28_*LA2-2iFa)!3rfzEm1u35uf)gxUM!*B+W4BYJ|DuXCi z1`||#WoThDbyh7w+A5pO{t?KE3C9(|))ipS15b$qV5{C8ZA*3_@RrX?pRau8oY&PK zNr7Hb4sc#Oz^uDE3*i9Zy$F>b5bQE?gK~h6j68`|Lh9Ea{NFE{G6MeG!B+Y_Ul7Rv zebJdd%q*{jK_F@^4xpa-9DV$2qWtC;e*~w^#76CcG6T!P=napY-v6z?vZv{PKm8$< z9Pa2hVtPk`)~OM#1#-GCv3xSf4|yZ|vOkCEv;Jv=eplF^5pK^PZ7Ut}Pao= z)Hxs2=bXM~&_9o)buNW@q%pqPLI3QqZ+6HxJM5nmY@Ho!n-y%I9_*MJ>Zl5}mkqX+ z4tA7PE{DGFbeh8AK7RruP zodAU)I$+W0N9#i$mbM07B5DGivx41I!#!moasy6~Ko{b)mF^5lXUH80#wvn2)roAi zKvK*{t|pA-06Y=x%hQ#O`tt^FUG{P5bKucuJn2ymKs7*G-;-asARTU6{2w4Uy^2#aQAP2 z^(X27_~$Nh)gkoNt;$Il>WUT+!wQrfCIZn4gx!nI>6FL&(st0>(zFr&K)|p!W7L~B z;wv6)tsZTiHH3_%b^Zu~eP_*Zd+m^~Ce%_J^wkEN!Tz}cWbG|z=LY<<`~5Ql{^_Ci z>Y=Wxq0Y+TwhAzQsJ$eN(B6)?j_6(r-iNz!#SrgHhdaQ2&T6P-x@-1pD5PhoHn9U( zq^9uZ`Ng+^`ps4SP1XHPew)l;>tX<8pv ziRKx|z-V#s&qIQ=y|ot7hxI`h43sZX8pn@N>jv8D2V3g~Tk8j*puTCJ73!)&tvtNA z1k?u$MTmlyHWnm8i?>)61x=yO)@nhZwFuTLfIPp_c~@iV_6Pstg!K9J`wll{4vZ^; z``@$WOVR;_gxk3d`y%$6GSX8rj6CW`-}|NXxvu%&8=TvYKlxRGqc_~&o^)Khj#dqiyQWj=4h}HKF$T!S*`b0s0 zway5)O&e*e4tG%w0}=<3rF0dCQE_z_QRMC{W8zYnhfa|4oU#yjPb~}WLIO7czb%Yc zf!_*E2beeIRuNeQY6@@jBI;KUG*=_`55NsrAAmCm#MY+jKvUI#yQ0ri1qbN!R`g+I zXacP0b60F_tlZvMz11^yn{W02q;*bz8)ZTLa0YkjA&4chAlaDm$E zf*rM?_Bo;M8N*a9lwoB+2&Y%V#6?~cx;cJZA<^12!U9M_kDiE66F}CnZdx4R@z0%~ zpS%U3*OwFU<)R&I$sVY4Y`b;o$6tNrRq1oXf{(W51#LxedqHT$?0f!dK9Ya;!jF1V zx8u&4Qy`FU``FGsvi14%KWNPzgbVd=_>@?F`P1Jmn{j6gd=F&_IlyphZV=1JOW*kg zww^uo!lKGiWLfXsrdEK#x7=S7hxi?yV+{1I|AH9*{KuC&rtGRq3Zgx^=bNxxIQHEc z#&$`K5UR1BU^V#uw`fcpHi!$#g3TPoDUfqe7oEgpxgCP^^l5p~(}!Eq=x4~9(}!BJ zcQzLe`4FmS40D(d`|HE4^&#Bu*4n|g8hTLPHgB*Unar#~qWko4>(o$tWw@<8*jYZ* z4q79qD;e!98SN?=LEeJm6_h2e6WzrDhS?bav5E3{%6TZvQ(a5KLz(-sLR%S9YlY+h zx0!P5yuw=>%eFOF2Z-@i7J&~`5$PeM&{hQ@o~nN33Gj;Yes9@;r>q~+Sh3Ar*4J3k z??#`g{ms++TITk*%;|5fLGnZXfOtSsI{-nQK+1f$L4RA_w$}PSC>=HZowLK8)x(_? zVM&lAcNYOyc%e{G0zdpgQVwp-N>m_Ky<(5Rj>7Odvk1O;?Av|oKNY_I^WnFXgs%VG z=(`?x=s!>DSFMu&;23NxKzH#_OXk4GcJ7vLuf6s<76cp;;(AMFVCjrIAO83$*@S;L zF8&X=5RL&`rEH(m2F*ga|eaF4e%zwfCN-`xn8l2L@!M*tdE~#&x906c?4NFIn`aE%dGn)U|N2uu ztc?$ti9QKa+#2!eZL@Q<)3jC=03-1)&{EX{d)Qmqn$Aym;p>+TK$-M1xETqr>lh{b$*9_pM)=W^6&muip^=@~3||vFDoyzx4b!p8kHAic-l)Vu3X{!{k!qH;1BMATO27p9X3ijdvP?-9} zezdZSg30Jd_Q{n)=(3IAN`z)QHOE_W1#SJr>h2GRXFs!|heU&I;5(^hA}(O`ZU1VxeGq zk&#pCs7h1{Q@tzzf`uF0Dg~P8AM)&v?b_qd9qcSZN=6^tK#l~m%GPBw@9Hk5kD6jD zLiiUxbWH5Ff3N)g73BKJWW@L6NKouvJ8hRdLLL9_8&AKqa_+rtxj`gFaDWd4|5xnq z+59D6)}SPE@NFzIyKZ_=HsRm(tsioy4!pJH!$1B(#I>yd?!4tutOiuD()as_s2S?28R?oc)H!>&V@9}h>R@LTSU%KV1}cN5 zgY6}Q9Njt7C>;S`B}bxzTyD%U`On50F?!CBE*pLA|iUk2Y6o^ zghfGe7&G~yw5q*m$e&MtY{io?;LQveHB)Y@VfNRRYzEPpsisI=p9pHHLh?hkfm#Q~ z2`vkxU_s#Zp?ms>9hK7cgPX-(kA^F4f-uAO@4J$F0;4(+_@ zA*<}V`Js^;?nlz!RuF2*3UrsqfHY25;n4PVpSp{QS}X`?tO?gRH*n0D79v$p?ugs36po-jA~3u}_`-{tG|*)zAL$ z!|(ob-y=^CZ2T0w1^$VHT!5Qe7{1Q?zI$%_;=Q*&ywUw$1b!Id7^s*rDV${Rx=-JE z(?j>&@yPAVKi)AV)SfrgmN$IY&0jpV@0&k;@wdPD$?v~<@x_ndd7!8CPE-!wbnttG zTB>M?_sDI0X<;PvKG$ed=5X_rVSm}qj;VL`%oy#O4Z06?%m{T(54Tr_+RF!#uXmMk zs?Ahmz7pG*jzU=x=ARHWwnR3WBSfIqS!9!SDCj2p8Agvlo5(`PMim8k-;y`jloe=n z^|@XBU_VR1m^mRc3GU+jIbN60~fW4mQZ0$t9$xS_)`2phZAP zAMpVc38)zavcii)pN9ph6qX(D)PbhyfflN&u{aENATPqQ&@j*nfiu+7XYx8{4tGr* z>Oy2iZXf|(3IkOlN8SX}*3x0}kW$nYR9ZA=4YcG0T2S?B$qsNeJct4pmy&l>`4x2R ziy{?Uk)2~f(9=Nyvpc4Q!Rf}7Z4Jp=8y#ESDcj*cR1>R}CsK~n8dWmP3?B5R(d%dI zh5k*hKGeZ#tw7mRf|D8stuYSbJ+Ys?g6!f3#Y6sVsuR!wTj?-LcP=Q}(Uuu%P95+# z``pg$p49%9j6iE{sB_AQKLJ8J+u+n$FL(SP?|CFItFuQ6;$J8Ai(?^lGcUBD} zx)a3}LFE|>kqoCp6x7*>Vx+1#2}%qm_aG>CfwY%mX9VibWD!Uffh3Xsl|9j?nx#$lNMZ>vFss9ncMj0XDNm3$GQlOqs!+lx{jy z9-q#RL@N-gc6j7Pr8^gu?pjoO=faX*3rco%m+pl0l_%}_p{`GN8B!W%HkicxM%{&MlXcEObT%RhiOEq-O^Xr>M*7EsF?Uglh(PNm6OzMl z@lZV6IwjbYHR#C*x?KTJM!z?+&*M^2pW4g;fksRDKtmb5_JRmgh0T$~ok?#RS&1-P zEF@N_Iw)ggM~ItCWD)TJraK^3g8{V_ZopgVy<5dV6MTTGYPD#PldwOqhis=+0wYh| z-aNg}KfAwqUZ1}%;CI6xhT3a}+h+y4t57uWSWvQaL5X^t3NErjIrnT%_-*5%o!7%3>=y4Cg^Wve#MwNNn}al35$MGJ1tp{O z?M+yUp{uP>x^V#VHM)`=NKzqCaQ}!s#luKgTZ_Vek-~6GVX&nz1ZgS^HWv)C1e@|n zX;P3BtwX#7L#70q3c{u?3b#{~;zP|q73XMI`6viYxddu@@(PpUD&8~iNtB%wu`>k~ zWreBANZb`@l9(B6LK-a^Qhx<$E>dhz36Dt@IPFMV!BBG!v)maX4wlXC%FS>CFY}n5_E5`&W+6yir_e5(7AO`I67`9c zR8%09;(ZCqi!*dX;3xJ+I{QJDpV22H07dJ7SW1MZko5b!{zKnC3`UWiF_7SLL^EK?Y&7Ghz! z=vve!W%Nyfn}Nq*JUwM5X6qGzJb{xOVmw-_1F*tbkjZRnL3ats>+Et?cH z^(ZLag!D-CTc-@QcONyUK4uC9(c%MmsOP5H`t%l+N;O;g=dUqw* zzr|Bc>wvrR4mUZ#?e3~uy;C8#nO*@W;q^iJ3@1)RdLlYVuh?(;0By4PjJS;nF#@2_ zo!c^Y11g102PmT!v}PFxh2`u95O@x66-WyObtvoimZA-K$_8ncN>tSYzUjf{=^1AIT50apPpcn53rB}h!03BZeT)sD5+?wg0~dG3c^F8A?>9*n~=!OkSqepB9L|N zfRweXct?BTNE78boW{6+{CNr%g2HbzxFfjMrm{Ze5@0+lriX~nkb*Jc16)z`c~D!I2bwAZ%@qS} z6~T_mq4x4{YiZC|gp?!HA_SU3f6ah1<{+XnLNWzr3C~joA>M+3m%^=33d{p*IV6L} z6ob)H&MiX0*o0sq$7T`i1&AHBMYe*V!cmUsk*$}7qL{n$P|SWA%?_166a=vjzz0wh zla!56XlIEeKVlKxwERPgVEr&h+6d&SiTY*3tvI!8itFwSu4o}Dzz01pasW>2iQ*m? zx>2hj)7=Vb9bjk(`<-XS}0laRBxum zfp?_EftCp3IzeK2^s>MZD~~|ZNvx3EK=Zo^r7($BObFlLgoj$aRrR++)lDG#h8S^b zzKVhNsu0|uy(-*M6>h799`ctDl9UZLmkcx)BV9of5)|n=uM{O~}V!gO}gkqUioOogmgXq!#pP9F)bh6woJ)=|wDY zT|}<{3er}N(5O%;SJ7pwK%z235(Q16bwG4h1WH{?`|_jA;Wk{foIq1n(Cq?usjg+N zN2n~x%vC{I3IGkJzR7<2>?ag%O$7@AIY7nMrg8}2W_QIMp32)jmD1kkuEd&fGYOQ+ zTi8ABa92?Az#kW-B!?3utN;}6iRH|7UM>VG2e3luiouf8E7l636=WZfmL8Qdn}yi} z)^)%JBa4P9{)&Ot>JWUulwf=HAli=Vh`={m%YzVKX|TCC&|HL;s#4_=X!A{Ckz(fS zDv*n-fanUUo{IV=grYnF{l#wWPmukG?dFb%-xf&WT$G6*tu`Xi8LGL^Ge6XvH_!$K zmyLGl_pi)vV!UMh5s}4#bfzr$3Vw$poMtGxf@FcN@*jfaEev5-kVc?awuK|UykJvS zz)jC{5bqJQA;@Y1ioPt8&sd?>X&vAeL>H*+oc!n&fMUFIfN?@gK?OMg^+8(>T?y$G zNRaNpngBOop_M^eID=>Et?ueuJycS2*-$B!1Fr_MAjmqvzQMc~2OuH6iXEVmglHW(P1mgpCA+>+Ap;DkHBC45h!XVvrpm4EEDEE#LrEZ~*%9Xv8bfp_;a` zGhoGl1lp@C){?=N!l41i2s!r_dT0ZBf&IJ!kVI%rE$2%L!XK=Rln%Tp z+Q>rAV-a#Q5^p}|KhZFeD-C_f!!6uX76+6HLh%7! z4V1`Zq9`czRk2)n94UO+Jt7GYLG))xiIZ6~Xh?cRKODecMeJ{{2q~^t^+OQmSr-{3 z2jG=~7Kcium?DmW7J_aA9n}LJSS6}i=jEamiB?6hrF0N3(Nr|pR7B1|{L2fu^T+`_ zc|lJeoB<@JcA&f_3WL}yOZBPNo`p_15;dqzWIzX`_6!vUD| zO6YN<(yins9p0j##CRK2dCqW0(WpN!?9D=K?nA0Wyr=h85l(AnPYy-kGmV)84H-mz z_<%cgfd2SUTCg!=(4CEo8Ez^LHCG1w(}L}@hWs_5w)&ve0U~VHFya7KXmyzKE!;B1 zR(fPa>i|c3E|-bx@Py5*-`W7)SKZo(7S4bK37HZcqxx2F_3iuuj;m)>9aMYt@hZVl zpA-@KP)5L05ooFm&^o~U7Fu&_CP)(aCEHO@9DpG!ktkoM&cJWkb+zdY$fNyEs5I94{}>Rv7Lo8|^CFp^9L30KEcq70c($ zpwkM_MI|p&oLUls{8m^)sT1fCeldL{vpE}CI3*-3ede=E=*kCJNEgU$WD~Cv)Hb^0 z54;Dwi0kP{b;3AM9ut?5G=n7!u2=MTP?g zM}+APu9GmN6+pPo&H$y1g;OJfBwMI3Ald4Hl%w573dt6(o8bwRBas_aLT({vsJhit zb(@DPX)l(AYHGdoSc#r2v11_1!V4kT`+FEJSOH>)So$^z4YJPf?$}A|@o= zgyjRiDp~>j6~R{W1f>4t1C#=B>?fi#*I^;9R|Z8Kz80GB3w_$g6KvI zMLUFCPPq!UwpE7xB|%?tumz=dA=T3!%8}q3*ELAXIj9jFfpbkJw) z;Q-~EiMY&is(R)5PZi2vdOFmMpo=<~lOHaEqZS0#**#)F=}C4LsUN6XU^hVKb6aD@ ztqqm8G+-$}0Zk5oWdTLA(joj#db79s4o~%FaRVwIXiXpoAU9AIGdVyrjOE)|h|}a1 zoZbkQCzftp?0# z;rcjet`gM3LTduX;l+VE40cS#5)tNZ5F}>7)(R{agZvCC=q(Jo3kFz_I1PAm2i>_) zlp7HBIh=dU%u3Up`T$a{MQ&iiL81{YIB3N~f?o0ga)S?d-os#lc+mLiy; zMflY?)`y}Ut@J1p0h=CTx-%)*6W6(-rAk-Deg)Mt{&bSY^nQ2x0CsVM>jfcC@nCaV zsD0{4`^@3CdEu_QAw=}f`o0bbI8EQG9c-T;XrJE?a)aXZrE^m{g#B#iFJQp|`i-{P zeg2t!Ez|p&rfzSl*wTb_ynJ(W#kQ96Z9cFT*@!#_Wo9#pql;kHEl^o3kX=Gn66lm5 zVSS*b0B(Rp2+0yWL6yrDC>Y2MNO)O52F35)ZgE%hlU5{D@Q129yz=rvy`0`m?=I-8 z$q<}{Bs`SoP?%@kTY>7CbW?aiprt?;!OZ?D`Y9zQG_%>ve-y1F=@20Co{}QwtFT`| z+QiUY3N-J{>?j(tZ?MAqvaTSn5>iFbT0yPait)Lq2(*+8v=jzfid3*y@g8+WZrGhO z=*|ha!D*}&Ib?)OFu$et5C;$uH(>UI_iV%p0KKJPupQ|Q2YAaf90~0jibXOdiua&? zN70Bsf2b*YkYCVl=l50+KoFfnKB`hGdHdb2{svdDF)h%THsH<}Y|Ny!&RZDpl_3NS zwa*@DpEul96Yi=Hb~OxkHt;9m>j&tEMe6ytc@XdCBccoYMf!#4t@H~F^g9gl<5aCR o{q1#qt#$oA`fmDwZ(iX411`bCRp2?nk^lez07*qoM6N<$g8bu}z5oCK literal 0 HcmV?d00001 From 9cfc4dc91b7ff2651e300b7dbbcaf711dc11872a Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 26 Jul 2017 15:21:39 -0700 Subject: [PATCH 34/95] Can drag blocks zip folder into hifi and upload the .obj --- interface/src/Application.cpp | 18 ++++++- interface/src/Application.h | 3 ++ .../src/FileScriptingInterface.cpp | 50 +++++++++++-------- .../src/FileScriptingInterface.h | 2 +- scripts/system/html/js/marketplacesInject.js | 24 +++++++-- scripts/system/html/marketplaces.html | 36 ++++++++----- 6 files changed, 95 insertions(+), 38 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dbb94cfdae..70ef794bfb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -229,6 +229,9 @@ static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString WEB_VIEW_TAG = "noDownload=true"; +// temporary zip handling for Emily +static const QString ZIP_EXTENSION = ".zip"; + static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; @@ -259,7 +262,10 @@ const QHash Application::_acceptedExtensi { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, { JSON_EXTENSION, &Application::importJSONFromURL }, { JS_EXTENSION, &Application::askToLoadScript }, - { FST_EXTENSION, &Application::askToSetAvatarUrl } + { FST_EXTENSION, &Application::askToSetAvatarUrl }, + + // temporary zip handling for Emily + { ZIP_EXTENSION, &Application::importFromZIP } }; class DeadlockWatchdogThread : public QThread { @@ -2738,6 +2744,14 @@ bool Application::importSVOFromURL(const QString& urlString) { return true; } +// temporary zip handling for Emily, not set to auto-add +bool Application::importFromZIP(const QString& filePath) { + qDebug() << "A zip file has been dropped in: " << filePath; + QUrl empty = ""; + qApp->getFileDownloadInterface()->runUnzip(filePath, empty, false, true); + return true; +} + bool _renderRequested { false }; bool Application::event(QEvent* event) { @@ -6156,7 +6170,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { if (tempFile.open(QIODevice::WriteOnly)) { tempFile.write(request->getData()); addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key. - qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true); + qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false); } else { QString errorInfo = "Couldn't open temporary file for download"; qWarning(interfaceapp) << errorInfo; diff --git a/interface/src/Application.h b/interface/src/Application.h index ce27c4a70a..e6ae970b61 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -478,6 +478,9 @@ private: bool importJSONFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString); + // temporary zip handling for Emily + bool importFromZIP(const QString& filePath); + bool nearbyEntitiesAreReadyForPhysics(); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket); diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 30d0a3a201..7d8458598d 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -32,12 +32,19 @@ FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent // nothing for now } -void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd) { +void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isBlocks) { qCDebug(scriptengine) << "Url that was downloaded: " + url.toString(); qCDebug(scriptengine) << "Path where download is saved: " + path; QString fileName = "/" + path.section("/", -1); QString tempDir = path; - tempDir.remove(fileName); + if (!isBlocks) { + tempDir.remove(fileName); + } else { + QTemporaryDir blocks; + tempDir = blocks.path(); + path.remove("file:///"); + } + qCDebug(scriptengine) << "Temporary directory at: " + tempDir; if (!isTempDir(tempDir)) { qCDebug(scriptengine) << "Temporary directory mismatch; risk of losing files"; @@ -45,6 +52,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd) { } QString file = unzipFile(path, tempDir); + qCDebug(scriptengine) << "Unzipped file: " << file; QString filename = QUrl::fromLocalFile(file).toString(); if (file != "") { qCDebug(scriptengine) << "File to upload: " + filename; @@ -54,6 +62,26 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd) { emit unzipResult(path, filename, autoAdd); } +QString FileScriptingInterface::unzipFile(QString path, QString tempDir) { + + QDir dir(path); + QString dirName = dir.path(); + qCDebug(scriptengine) << "Directory to unzip: " << dirName; + QString target = tempDir + "/model_repo"; + QStringList list = JlCompress::extractDir(dirName, target); + + qCDebug(scriptengine) << list; + + if (!list.isEmpty()) { + return list.front(); + } + else { + qCDebug(scriptengine) << "Extraction failed"; + return ""; + } + +} + // fix to check that we are only referring to a temporary directory bool FileScriptingInterface::isTempDir(QString tempDir) { QString folderName = "/" + tempDir.section("/", -1); @@ -92,24 +120,6 @@ void FileScriptingInterface::downloadZip(QString path, const QString link) { request->send(); } -QString FileScriptingInterface::unzipFile(QString path, QString tempDir) { - - QDir dir(path); - QString dirName = dir.path(); - QString target = tempDir + "/model_repo"; - QStringList list = JlCompress::extractDir(dirName, target); - - qCDebug(scriptengine) << list; - - if (!list.isEmpty()) { - return list.front(); - } else { - qCDebug(scriptengine) << "Extraction failed"; - return ""; - } - -} - // this function is not in use void FileScriptingInterface::recursiveFileScan(QFileInfo file, QString* dirName) { /*if (!file.isDir()) { diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h index 5e9a6029e8..dc5ffdace8 100644 --- a/libraries/script-engine/src/FileScriptingInterface.h +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -24,7 +24,7 @@ public: public slots: QString convertUrlToPath(QUrl url); - void runUnzip(QString path, QUrl url, bool autoAdd); + void runUnzip(QString path, QUrl url, bool autoAdd, bool isBlocks); QString getTempDir(); signals: diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 45b2e99018..0ee337a2ef 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -33,8 +33,8 @@ $("head").append( '' + ); + } + function updateClaraCode() { // Have to repeatedly update Clara page because its content can change dynamically without location.href changing. @@ -322,10 +335,12 @@ var DIRECTORY = 0; var HIFI = 1; - var CLARA = 2; + var BLOCKS = 2; + var CLARA = 3; var pageType = DIRECTORY; if (location.href.indexOf("highfidelity.com/") !== -1) { pageType = HIFI; } + if (location.href.indexOf("google.com/") !== -1) { pageType = BLOCKS; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } injectCommonCode(pageType === DIRECTORY); @@ -336,6 +351,9 @@ case HIFI: injectHiFiCode(); break; + case BLOCKS: + injectBlocksCode(); + break; case CLARA: injectClaraCode(); break; diff --git a/scripts/system/html/marketplaces.html b/scripts/system/html/marketplaces.html index 6051a9df96..8c5fe15429 100644 --- a/scripts/system/html/marketplaces.html +++ b/scripts/system/html/marketplaces.html @@ -30,19 +30,31 @@
-
-
- +
+
+
+ +
+
+

Blocks, released by Google, allows anyone to create 3D models using just a few simple tools. Browse through other users' creations for low-poly assets to add to your world.

+
+
-
-

Clara.io has thousands of models available for importing into High Fidelity. Follow these steps for the best experience:

-
    -
  1. Create an account here or log in as an existing user.
  2. -
  3. Choose a model from the list and click “Download to High Fidelity”.
  4. -
-
- -
+
+
+
+
+
+ +
+
+

Clara.io has thousands of models available for importing into High Fidelity. Follow these steps for the best experience:

+
    +
  1. Create an account here or log in as an existing user.
  2. +
  3. Choose a model from the list and click “Download to High Fidelity”.
  4. +
+
+
From acb088b263bf1027b6c11eaf02eea8bc4d8c6993 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 26 Jul 2017 16:58:23 -0700 Subject: [PATCH 35/95] Blocks drag does not work yet --- interface/src/Application.cpp | 23 +++++++++++++++---- interface/src/Application.h | 4 ++-- .../src/FileScriptingInterface.cpp | 21 +++++++++-------- .../src/FileScriptingInterface.h | 4 ++-- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 70ef794bfb..fe75242c2f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6200,12 +6200,21 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { addAssetToWorldError(filename, "Couldn't unzip file " + filename + "."); } -void Application::addAssetToWorld(QString filePath) { +void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBlocks) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). + qCDebug(interfaceapp) << "File about to be uploaded: " << filePath; + qCDebug(interfaceapp) << "Original zip folder: " << zipFile; QString path = QUrl(filePath).toLocalFile(); QString filename = filenameFromPath(path); - QString mapping = "/" + filename; + QString mapping; + if (isBlocks) { + QString assetFolder = zipFile.section("/", -1); + assetFolder.remove(".zip"); + mapping = "/" + assetFolder + "/" + filename; + } else { + mapping = "/" + filename; + } // Test repeated because possibly different code paths. if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { @@ -6576,15 +6585,19 @@ void Application::onAssetToWorldMessageBoxClosed() { } -void Application::handleUnzip(QString zipFile, QString unzipFile, bool autoAdd) { +void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isBlocks) { if (autoAdd) { if (!unzipFile.isEmpty()) { - addAssetToWorld(unzipFile); + qCDebug(interfaceapp) << "My folder contents: " << unzipFile; + for (int i = 0; i < unzipFile.length(); i++) { + qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i); + addAssetToWorld(unzipFile.at(i), zipFile, isBlocks); + } } else { addAssetToWorldUnzipFailure(zipFile); } } else { - showAssetServerWidget(unzipFile); + showAssetServerWidget(unzipFile.first()); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index e6ae970b61..54d4a9ef90 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -331,14 +331,14 @@ public slots: // FIXME: Move addAssetToWorld* methods to own class? void addAssetToWorldFromURL(QString url); void addAssetToWorldFromURLRequestFinished(); - void addAssetToWorld(QString filePath); + void addAssetToWorld(QString filePath, QString zipFile, bool isBlocks); void addAssetToWorldUnzipFailure(QString filePath); void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy); void addAssetToWorldUpload(QString filePath, QString mapping); void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash); void addAssetToWorldAddEntity(QString filePath, QString mapping); - void handleUnzip(QString sourceFile, QString destinationFile, bool autoAdd); + void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isBlocks); FileScriptingInterface* getFileDownloadInterface() { return _fileDownload; } diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 7d8458598d..5ba2868365 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -51,18 +51,21 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool return; } - QString file = unzipFile(path, tempDir); - qCDebug(scriptengine) << "Unzipped file: " << file; - QString filename = QUrl::fromLocalFile(file).toString(); - if (file != "") { + QStringList fileList = unzipFile(path, tempDir); + qCDebug(scriptengine) << "Unzipped file list: " << fileList; + QString filename = QUrl::fromLocalFile(fileList.first()).toString(); + + if (filename != "") { qCDebug(scriptengine) << "File to upload: " + filename; - } else { + } + else { qCDebug(scriptengine) << "Unzip failed"; } - emit unzipResult(path, filename, autoAdd); + emit unzipResult(path, fileList, autoAdd, isBlocks); + } -QString FileScriptingInterface::unzipFile(QString path, QString tempDir) { +QStringList FileScriptingInterface::unzipFile(QString path, QString tempDir) { QDir dir(path); QString dirName = dir.path(); @@ -73,11 +76,11 @@ QString FileScriptingInterface::unzipFile(QString path, QString tempDir) { qCDebug(scriptengine) << list; if (!list.isEmpty()) { - return list.front(); + return list; } else { qCDebug(scriptengine) << "Extraction failed"; - return ""; + return list; } } diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h index dc5ffdace8..806fa7fd9b 100644 --- a/libraries/script-engine/src/FileScriptingInterface.h +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -28,11 +28,11 @@ public slots: QString getTempDir(); signals: - void unzipResult(QString zipFile, QString unzipFile, bool autoAdd); + void unzipResult(QString zipFile, QStringList unzipFile, bool autoAdd, bool isBlocks); private: bool isTempDir(QString tempDir); - QString unzipFile(QString path, QString tempDir); + QStringList unzipFile(QString path, QString tempDir); void recursiveFileScan(QFileInfo file, QString* dirName); void downloadZip(QString path, const QString link); From 5e4a83dad97c1898054245c796c7f6b0b5258385 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 26 Jul 2017 17:58:39 -0700 Subject: [PATCH 36/95] defaultRenderStates, handControllerGrab.js, fix teleport.js a little --- interface/src/raypick/LaserPointer.cpp | 163 ++++--- interface/src/raypick/LaserPointer.h | 20 +- interface/src/raypick/LaserPointerManager.cpp | 6 +- interface/src/raypick/LaserPointerManager.h | 4 +- .../LaserPointerScriptingInterface.cpp | 17 +- .../system/controllers/handControllerGrab.js | 443 +++++++----------- scripts/system/controllers/teleport.js | 33 +- 7 files changed, 322 insertions(+), 364 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 76ed632027..23adf5b532 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -13,18 +13,25 @@ #include "Application.h" #include "avatar/AvatarManager.h" -LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : +LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), + _defaultRenderStates(defaultRenderStates), _faceAvatar(faceAvatar), _centerEndY(centerEndY), _lockEnd(lockEnd) { _rayPickUID = DependencyManager::get()->createRayPick(rayProps); - for (auto& state : _renderStates.keys()) { + for (QString& state : _renderStates.keys()) { if (!enabled || state != _currentRenderState) { - disableRenderState(state); + disableRenderState(_renderStates[state]); + } + } + for (QString& state : _defaultRenderStates.keys()) { + if (!enabled || state != _currentRenderState) { + disableRenderState(_defaultRenderStates[state].second); } } } @@ -42,6 +49,17 @@ LaserPointer::~LaserPointer() { qApp->getOverlays().deleteOverlay(renderState.getEndID()); } } + for (QPair& renderState : _defaultRenderStates) { + if (!renderState.second.getStartID().isNull()) { + qApp->getOverlays().deleteOverlay(renderState.second.getStartID()); + } + if (!renderState.second.getPathID().isNull()) { + qApp->getOverlays().deleteOverlay(renderState.second.getPathID()); + } + if (!renderState.second.getEndID().isNull()) { + qApp->getOverlays().deleteOverlay(renderState.second.getEndID()); + } + } } void LaserPointer::enable() { @@ -52,14 +70,24 @@ void LaserPointer::enable() { void LaserPointer::disable() { DependencyManager::get()->disableRayPick(_rayPickUID); _renderingEnabled = false; - if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { - disableRenderState(_currentRenderState); + if (!_currentRenderState.isEmpty()) { + if (_renderStates.contains(_currentRenderState)) { + disableRenderState(_renderStates[_currentRenderState]); + } + if (_defaultRenderStates.contains(_currentRenderState)) { + disableRenderState(_defaultRenderStates[_currentRenderState].second); + } } } void LaserPointer::setRenderState(const QString& state) { - if (!_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState)) { - disableRenderState(_currentRenderState); + if (!_currentRenderState.isEmpty()) { + if (_renderStates.contains(_currentRenderState)) { + disableRenderState(_renderStates[_currentRenderState]); + } + if (_defaultRenderStates.contains(_currentRenderState)) { + disableRenderState(_defaultRenderStates[_currentRenderState].second); + } } _currentRenderState = state; } @@ -85,77 +113,90 @@ OverlayID LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVar return OverlayID(); } -void LaserPointer::disableRenderState(const QString& renderState) { - if (!_renderStates[renderState].getStartID().isNull()) { +void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState) { + PickRay pickRay = DependencyManager::get()->getPickRay(_rayPickUID); + if (!renderState.getStartID().isNull()) { + QVariantMap startProps; + startProps.insert("position", vec3toVariant(pickRay.origin)); + startProps.insert("visible", true); + startProps.insert("ignoreRayIntersection", renderState.doesStartIgnoreRays()); + qApp->getOverlays().editOverlay(renderState.getStartID(), startProps); + } + glm::vec3 endVec; + if (defaultState || !_lockEnd || type == IntersectionType::HUD) { + endVec = pickRay.origin + pickRay.direction * distance; + } + else { + if (type == IntersectionType::ENTITY) { + endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; + } + else if (type == IntersectionType::OVERLAY) { + endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); + } + else if (type == IntersectionType::AVATAR) { + endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); + } + } + QVariant end = vec3toVariant(endVec); + if (!renderState.getPathID().isNull()) { + QVariantMap pathProps; + pathProps.insert("start", vec3toVariant(pickRay.origin)); + pathProps.insert("end", end); + pathProps.insert("visible", true); + pathProps.insert("ignoreRayIntersection", renderState.doesPathIgnoreRays()); + qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps); + } + if (!renderState.getEndID().isNull()) { + QVariantMap endProps; + if (_centerEndY) { + endProps.insert("position", end); + } + else { + glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value); + endProps.insert("position", vec3toVariant(endVec + glm::vec3(0, 0.5f * dim.y, 0))); + } + if (_faceAvatar) { + glm::quat rotation = glm::inverse(glm::quat_cast(glm::lookAt(endVec, DependencyManager::get()->getMyAvatar()->getPosition(), Vectors::UP))); + endProps.insert("rotation", quatToVariant(glm::quat(glm::radians(glm::vec3(0, glm::degrees(safeEulerAngles(rotation)).y, 0))))); + } + endProps.insert("visible", true); + endProps.insert("ignoreRayIntersection", renderState.doesEndIgnoreRays()); + qApp->getOverlays().editOverlay(renderState.getEndID(), endProps); + } +} + +void LaserPointer::disableRenderState(const RenderState& renderState) { + if (!renderState.getStartID().isNull()) { QVariantMap startProps; startProps.insert("visible", false); startProps.insert("ignoreRayIntersection", true); - qApp->getOverlays().editOverlay(_renderStates[renderState].getStartID(), startProps); + qApp->getOverlays().editOverlay(renderState.getStartID(), startProps); } - if (!_renderStates[renderState].getPathID().isNull()) { + if (!renderState.getPathID().isNull()) { QVariantMap pathProps; pathProps.insert("visible", false); pathProps.insert("ignoreRayIntersection", true); - qApp->getOverlays().editOverlay(_renderStates[renderState].getPathID(), pathProps); + qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps); } - if (!_renderStates[renderState].getEndID().isNull()) { + if (!renderState.getEndID().isNull()) { QVariantMap endProps; endProps.insert("visible", false); endProps.insert("ignoreRayIntersection", true); - qApp->getOverlays().editOverlay(_renderStates[renderState].getEndID(), endProps); + qApp->getOverlays().editOverlay(renderState.getEndID(), endProps); } } void LaserPointer::update() { RayPickResult prevRayPickResult = DependencyManager::get()->getPrevRayPickResult(_rayPickUID); if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState) && prevRayPickResult.type != IntersectionType::NONE) { - PickRay pickRay = DependencyManager::get()->getPickRay(_rayPickUID); - if (!_renderStates[_currentRenderState].getStartID().isNull()) { - QVariantMap startProps; - startProps.insert("position", vec3toVariant(pickRay.origin)); - startProps.insert("visible", true); - startProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesStartIgnoreRays()); - qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getStartID(), startProps); - } - glm::vec3 endVec; - if (!_lockEnd || prevRayPickResult.type == IntersectionType::HUD) { - endVec = pickRay.origin + pickRay.direction * prevRayPickResult.distance; - } else { - if (prevRayPickResult.type == IntersectionType::ENTITY) { - endVec = DependencyManager::get()->getEntityTransform(prevRayPickResult.objectID)[3]; - } else if (prevRayPickResult.type == IntersectionType::OVERLAY) { - endVec = vec3FromVariant(qApp->getOverlays().getProperty(prevRayPickResult.objectID, "position").value); - } else if (prevRayPickResult.type == IntersectionType::AVATAR) { - endVec = DependencyManager::get()->getAvatar(prevRayPickResult.objectID)->getPosition(); - } - } - QVariant end = vec3toVariant(endVec); - if (!_renderStates[_currentRenderState].getPathID().isNull()) { - QVariantMap pathProps; - pathProps.insert("start", vec3toVariant(pickRay.origin)); - pathProps.insert("end", end); - pathProps.insert("visible", true); - pathProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesPathIgnoreRays()); - qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getPathID(), pathProps); - } - if (!_renderStates[_currentRenderState].getEndID().isNull()) { - QVariantMap endProps; - if (_centerEndY) { - endProps.insert("position", end); - } else { - glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(_renderStates[_currentRenderState].getEndID(), "dimensions").value); - endProps.insert("position", vec3toVariant(endVec + glm::vec3(0, 0.5f * dim.y, 0))); - } - if (_faceAvatar) { - glm::quat rotation = glm::inverse(glm::quat_cast(glm::lookAt(endVec, DependencyManager::get()->getMyAvatar()->getPosition(), Vectors::UP))); - endProps.insert("rotation", quatToVariant(glm::quat(glm::radians(glm::vec3(0, glm::degrees(safeEulerAngles(rotation)).y, 0))))); - } - endProps.insert("visible", true); - endProps.insert("ignoreRayIntersection", _renderStates[_currentRenderState].doesEndIgnoreRays()); - qApp->getOverlays().editOverlay(_renderStates[_currentRenderState].getEndID(), endProps); - } - } else { - disableRenderState(_currentRenderState); + updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, prevRayPickResult.distance, prevRayPickResult.objectID, false); + disableRenderState(_defaultRenderStates[_currentRenderState].second); + } else if (_renderingEnabled && !_currentRenderState.isEmpty() && _defaultRenderStates.contains(_currentRenderState)) { + disableRenderState(_renderStates[_currentRenderState]); + updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), true); + } else if (!_currentRenderState.isEmpty()) { + disableRenderState(_renderStates[_currentRenderState]); + disableRenderState(_defaultRenderStates[_currentRenderState].second); } } diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index b1b8be23e4..34d9ee50df 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -26,15 +26,15 @@ public: RenderState() {} RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID); - const OverlayID& getStartID() { return _startID; } - const OverlayID& getPathID() { return _pathID; } - const OverlayID& getEndID() { return _endID; } + const OverlayID& getStartID() const { return _startID; } + const OverlayID& getPathID() const { return _pathID; } + const OverlayID& getEndID() const { return _endID; } void setStartID(const OverlayID& startID) { _startID = startID; } void setPathID(const OverlayID& pathID) { _pathID = pathID; } void setEndID(const OverlayID& endID) { _endID = endID; } - const bool& doesStartIgnoreRays() { return _startIgnoreRays; } - const bool& doesPathIgnoreRays() { return _pathIgnoreRays; } - const bool& doesEndIgnoreRays() { return _endIgnoreRays; } + const bool& doesStartIgnoreRays() const { return _startIgnoreRays; } + const bool& doesPathIgnoreRays() const { return _pathIgnoreRays; } + const bool& doesEndIgnoreRays() const { return _endIgnoreRays; } private: OverlayID _startID; @@ -49,8 +49,8 @@ private: class LaserPointer { public: - LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, - const bool lockEnd, const bool enabled); + LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); ~LaserPointer(); QUuid getRayUID() { return _rayPickUID; } @@ -74,6 +74,7 @@ private: bool _renderingEnabled; QString _currentRenderState { "" }; QHash _renderStates; + QHash> _defaultRenderStates; bool _faceAvatar; bool _centerEndY; bool _lockEnd; @@ -81,7 +82,8 @@ private: QUuid _rayPickUID; OverlayID updateRenderStateOverlay(const OverlayID& id, const QVariant& props); - void disableRenderState(const QString& renderState); + void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState); + void disableRenderState(const RenderState& renderState); }; #endif // hifi_LaserPointer_h diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 2b4d7d096b..b05f56fa53 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -12,9 +12,9 @@ #include "LaserPointer.h" #include "RayPick.h" -QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, - const bool lockEnd, const bool enabled) { - std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, faceAvatar, centerEndY, lockEnd, enabled); +QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { + std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); if (laserPointer->getRayUID() != 0) { QWriteLocker lock(&_addLock); QUuid id = QUuid::createUuid(); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index b239fc1514..db035b197f 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -25,8 +25,8 @@ class LaserPointerManager : public Dependency { SINGLETON_DEPENDENCY public: - QUuid createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, const bool faceAvatar, const bool centerEndY, - const bool lockEnd, const bool enabled); + QUuid createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); void removeLaserPointer(const QUuid uid); void enableLaserPointer(const QUuid uid); void disableLaserPointer(const QUuid uid); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 7cae7ccdc4..9bda37f26f 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -54,7 +54,22 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert } } - return DependencyManager::get()->createLaserPointer(propertyMap, renderStates, faceAvatar, centerEndY, lockEnd, enabled); + QHash> defaultRenderStates; + if (propertyMap["defaultRenderStates"].isValid()) { + QList renderStateVariants = propertyMap["defaultRenderStates"].toList(); + for (QVariant& renderStateVariant : renderStateVariants) { + if (renderStateVariant.isValid()) { + QVariantMap renderStateMap = renderStateVariant.toMap(); + if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) { + QString name = renderStateMap["name"].toString(); + float distance = renderStateMap["distance"].toFloat(); + defaultRenderStates[name] = QPair(distance, buildRenderState(renderStateMap)); + } + } + } + } + + return DependencyManager::get()->createLaserPointer(propertyMap, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); } void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& renderState, const QVariant& properties) { diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 04921fe14d..96d2b0d3fa 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -64,8 +64,6 @@ var HAPTIC_STYLUS_DURATION = 20.0; var HAPTIC_LASER_UI_STRENGTH = 1.0; var HAPTIC_LASER_UI_DURATION = 20.0; -var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move. - var PICK_WITH_HAND_RAY = true; var EQUIP_SPHERE_SCALE_FACTOR = 0.65; @@ -157,7 +155,6 @@ var INCHES_TO_METERS = 1.0 / 39.3701; // these control how long an abandoned pointer line or action will hang around var ACTION_TTL = 15; // seconds var ACTION_TTL_REFRESH = 5; -var PICKS_PER_SECOND_PER_HAND = 60; var MSECS_PER_SEC = 1000.0; var GRABBABLE_PROPERTIES = [ "position", @@ -448,15 +445,6 @@ function entityHasActions(entityID) { return Entities.getActionIDs(entityID).length > 0; } -function findRayIntersection(pickRay, precise, include, exclude) { - var entities = Entities.findRayIntersection(pickRay, precise, include, exclude, true); - var overlays = Overlays.findRayIntersection(pickRay, precise, [], [HMD.tabletID]); - if (!overlays.intersects || (entities.intersects && (entities.distance <= overlays.distance))) { - return entities; - } - return overlays; -} - function entityIsGrabbedByOther(entityID) { // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. var actionIDs = Entities.getActionIDs(entityID); @@ -1043,6 +1031,74 @@ function getControllerJointIndex(hand) { // global EquipHotspotBuddy instance var equipHotspotBuddy = new EquipHotspotBuddy(); +var halfPath = { + type: "line3d", + color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + parentID: AVATAR_SELF_ID +} +var halfEnd = { + type: "sphere", + solid: true, + color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + alpha: 0.9, + ignoreRayIntersection: true, + drawInFront: true, // Even when burried inside of something, show it. + visible: true +} +var fullPath = { + type: "line3d", + color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + parentID: AVATAR_SELF_ID +} +var fullEnd = { + type: "sphere", + solid: true, + color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, + alpha: 0.9, + ignoreRayIntersection: true, + drawInFront: true, // Even when burried inside of something, show it. + visible: true +} +var holdPath = { + type: "line3d", + color: COLORS_GRAB_DISTANCE_HOLD, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + parentID: AVATAR_SELF_ID +} + +var renderStates = [{name: "half", path: halfPath, end: halfEnd}, + {name: "full", path: fullPath, end: fullEnd}, + {name: "hold", path: holdPath}]; +var headRenderStates = [{name: "half", end: halfEnd}, + {name: "full", end: fullEnd}, + {name: "hold", path: holdPath}]; + +// how far from camera to search intersection? +var DEFAULT_SEARCH_SPHERE_DISTANCE = 1000; +var defaultRenderStates = [{name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, + {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, + {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath}]; + function MyController(hand) { this.hand = hand; this.autoUnequipCounter = 0; @@ -1091,7 +1147,6 @@ function MyController(hand) { this.grabbedThingID = null; // on this entity. this.grabbedOverlay = null; this.state = STATE_OFF; - this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value this.triggerClicked = false; @@ -1100,18 +1155,33 @@ function MyController(hand) { this.rawThumbValue = 0; // for visualizations - this.overlayLine = null; - this.searchSphere = null; - this.otherGrabbingLine = null; + this.halfEnd = halfEnd; + this.fullEnd = fullEnd; + this.laserPointer = LaserPointers.createLaserPointer({ + joint: (hand == RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + maxDistance: PICK_MAX_DISTANCE, + posOffset: getGrabPointSphereOffset(this.handToController()), + renderStates: renderStates, + faceAvatar: true, + defaultRenderStates: defaultRenderStates + }); + this.headLaserPointer = LaserPointers.createLaserPointer({ + joint: "Avatar", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + maxDistance: PICK_MAX_DISTANCE, + renderStates: headRenderStates, + faceAvatar: true, + defaultRenderStates: defaultRenderStates + }); + LaserPointers.setIgnoreOverlays(this.laserPointer, [HMD.tabletID]); + LaserPointers.setIgnoreOverlays(this.headLaserPointer, [HMD.tabletID]); this.otherGrabbingUUID = null; this.waitForTriggerRelease = false; - // how far from camera to search intersection? - var DEFAULT_SEARCH_SPHERE_DISTANCE = 1000; this.intersectionDistance = 0.0; - this.searchSphereDistance = DEFAULT_SEARCH_SPHERE_DISTANCE; this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; @@ -1292,41 +1362,6 @@ function MyController(hand) { } }; - this.searchSphereOn = function(location, size, color) { - - var rotation = Quat.lookAt(location, Camera.getPosition(), Vec3.UP); - var brightColor = colorPow(color, 0.06); - if (this.searchSphere === null) { - var sphereProperties = { - name: "searchSphere", - position: location, - rotation: rotation, - outerRadius: size * 1.2, - innerColor: brightColor, - outerColor: color, - innerAlpha: 0.9, - outerAlpha: 0.0, - solid: true, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - this.searchSphere = Overlays.addOverlay("circle3d", sphereProperties); - } else { - Overlays.editOverlay(this.searchSphere, { - position: location, - rotation: rotation, - innerColor: brightColor, - outerColor: color, - innerAlpha: 1.0, - outerAlpha: 0.0, - outerRadius: size * 1.2, - visible: true, - ignoreRayIntersection: true - }); - } - }; - this.showStylus = function() { if (this.stylus) { return; @@ -1362,97 +1397,32 @@ function MyController(hand) { this.stylus = null; }; - this.overlayLineOn = function(closePoint, farPoint, color, farParentID) { - if (this.overlayLine === null) { - var lineProperties = { - name: "line", - glow: 1.0, - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - visible: true, - alpha: 1, - parentID: AVATAR_SELF_ID, - parentJointIndex: MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"), - endParentID: farParentID - }; - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - if (farParentID && farParentID != NULL_UUID) { - Overlays.editOverlay(this.overlayLine, { - color: color, - endParentID: farParentID - }); - } else { - Overlays.editOverlay(this.overlayLine, { - length: Vec3.distance(farPoint, closePoint), - color: color, - endParentID: farParentID - }); - } - } - }; - - this.searchIndicatorOn = function(distantPickRay) { - var handPosition = distantPickRay.origin; + this.updateLaserPointer = function() { var SEARCH_SPHERE_SIZE = 0.011; - var SEARCH_SPHERE_FOLLOW_RATE = 0.50; - - if (this.intersectionDistance > 0) { - // If we hit something with our pick ray, move the search sphere toward that distance - this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + - this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); + var radius = 1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance; + var dim = {x: radius, y: radius, z: radius}; + var mode = "hold"; + if (this.state !== STATE_DISTANCE_HOLDING && this.state !== STATE_DISTANCE_ROTATING) { + mode = (this.triggerSmoothedGrab() || this.secondarySqueezed()) ? "full" : "half"; } - var searchSphereLocation = Vec3.sum(distantPickRay.origin, - Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); - this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance, - (this.triggerSmoothedGrab() || this.secondarySqueezed()) ? - COLORS_GRAB_SEARCHING_FULL_SQUEEZE : - COLORS_GRAB_SEARCHING_HALF_SQUEEZE); - if (PICK_WITH_HAND_RAY) { - this.overlayLineOn(handPosition, searchSphereLocation, - (this.triggerSmoothedGrab() || this.secondarySqueezed()) ? - COLORS_GRAB_SEARCHING_FULL_SQUEEZE : - COLORS_GRAB_SEARCHING_HALF_SQUEEZE); + var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer; + if (mode === "full") { + var fullEndToEdit = PICK_WITH_HAND_RAY ? this.fullEnd : fullEnd; + fullEndToEdit.dimensions = dim; + LaserPointers.editRenderState(laserPointerID, mode, {path: fullPath, end: fullEndToEdit}); + } else if (mode === "half") { + var halfEndToEdit = PICK_WITH_HAND_RAY ? this.halfEnd : halfEnd; + halfEndToEdit.dimensions = dim; + LaserPointers.editRenderState(laserPointerID, mode, {path: halfPath, end: halfEndToEdit}); } + LaserPointers.enableLaserPointer(laserPointerID); + LaserPointers.setRenderState(laserPointerID, mode); }; - // Turns off indicators used for searching. Overlay line and sphere. - this.searchIndicatorOff = function() { - this.searchSphereOff(); - if (PICK_WITH_HAND_RAY) { - this.overlayLineOff(); - } - }; - - this.otherGrabbingLineOn = function(avatarPosition, entityPosition, color) { - if (this.otherGrabbingLine === null) { - var lineProperties = { - lineWidth: 5, - start: avatarPosition, - end: entityPosition, - color: color, - glow: 1.0, - ignoreRayIntersection: true, - drawInFront: true, - visible: true, - alpha: 1 - }; - this.otherGrabbingLine = Overlays.addOverlay("line3d", lineProperties); - } else { - Overlays.editOverlay(this.otherGrabbingLine, { - start: avatarPosition, - end: entityPosition, - color: color - }); - } + this.laserPointerOff = function() { + var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer; + LaserPointers.disableLaserPointer(laserPointerID); }; this.evalLightWorldTransform = function(modelPos, modelRot) { @@ -1475,42 +1445,9 @@ function MyController(hand) { }; }; - this.lineOff = function() { - if (this.pointer !== null) { - Entities.deleteEntity(this.pointer); - } - this.pointer = null; - }; - - this.overlayLineOff = function() { - if (this.overlayLine !== null) { - Overlays.deleteOverlay(this.overlayLine); - } - this.overlayLine = null; - }; - - this.searchSphereOff = function() { - if (this.searchSphere !== null) { - Overlays.deleteOverlay(this.searchSphere); - this.searchSphere = null; - this.searchSphereDistance = DEFAULT_SEARCH_SPHERE_DISTANCE; - this.intersectionDistance = 0.0; - } - }; - - this.otherGrabbingLineOff = function() { - if (this.otherGrabbingLine !== null) { - Overlays.deleteOverlay(this.otherGrabbingLine); - } - this.otherGrabbingLine = null; - }; - this.turnOffVisualizations = function() { - this.overlayLineOff(); this.grabPointSphereOff(); - this.lineOff(); - this.searchSphereOff(); - this.otherGrabbingLineOff(); + this.laserPointerOff(); restore2DMode(); }; @@ -1803,9 +1740,9 @@ function MyController(hand) { // Always showing lasers while in edit mode and hands/stylus is not active. var rayPickInfo = this.calcRayPickInfo(this.hand); this.intersectionDistance = (rayPickInfo.entityID || rayPickInfo.overlayID) ? rayPickInfo.distance : 0; - this.searchIndicatorOn(rayPickInfo.searchRay); + this.updateLaserPointer(); } else { - this.searchIndicatorOff(); + this.laserPointerOff(); } }; @@ -1846,27 +1783,18 @@ function MyController(hand) { // Performs ray pick test from the hand controller into the world // @param {number} which hand to use, RIGHT_HAND or LEFT_HAND - // @param {object} if set, use this as as the pick ray, expects origin, direction, and length fields. // @returns {object} returns object with two keys entityID and distance // - this.calcRayPickInfo = function(hand, pickRayOverride) { + this.calcRayPickInfo = function(hand) { + var controllerLocation = getControllerWorldLocation(this.handToController(), true); + var worldHandPosition = controllerLocation.position; + var worldHandRotation = controllerLocation.orientation; - var pickRay; - if (pickRayOverride) { - pickRay = pickRayOverride; - } else { - var controllerLocation = getControllerWorldLocation(this.handToController(), true); - var worldHandPosition = controllerLocation.position; - var worldHandRotation = controllerLocation.orientation; - - pickRay = { - origin: PICK_WITH_HAND_RAY ? worldHandPosition : Camera.position, - direction: PICK_WITH_HAND_RAY ? Quat.getUp(worldHandRotation) : Vec3.mix(Quat.getUp(worldHandRotation), - Quat.getFront(Camera.orientation), - HAND_HEAD_MIX_RATIO), - length: PICK_MAX_DISTANCE - }; - } + var pickRay = { + origin: PICK_WITH_HAND_RAY ? worldHandPosition : MyAvatar.getHeadPosition(), + direction: PICK_WITH_HAND_RAY ? Quat.getUp(worldHandRotation) : Quat.getFront(Camera.orientation), + length: PICK_MAX_DISTANCE + }; var result = { entityID: null, @@ -1875,28 +1803,17 @@ function MyController(hand) { distance: PICK_MAX_DISTANCE }; - var now = Date.now(); - if (now - this.lastPickTime < MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - return result; - } - this.lastPickTime = now; + var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer; + var intersection = LaserPointers.getPrevRayPickResult(laserPointerID); - var intersection; - if (USE_BLACKLIST === true && blacklist.length !== 0) { - intersection = findRayIntersection(pickRay, true, [], blacklist, true); - } else { - intersection = findRayIntersection(pickRay, true, [], [], true); - } - - if (intersection.intersects) { + if (intersection.type != RayPick.INTERSECTED_NONE) { return { - entityID: intersection.entityID, - overlayID: intersection.overlayID, + entityID: intersection.type == RayPick.INTERSECTED_ENTITY ? intersection.objectID : null, + overlayID: intersection.type == RayPick.INTERSECTED_OVERLAY ? intersection.objectID : null, searchRay: pickRay, - distance: Vec3.distance(pickRay.origin, intersection.intersection), + distance: intersection.distance, intersection: intersection.intersection, - normal: intersection.surfaceNormal, - properties: intersection.properties + normal: intersection.surfaceNormal }; } else { return result; @@ -2168,7 +2085,6 @@ function MyController(hand) { var rayPickInfo = this.calcRayPickInfo(this.hand); if (rayPickInfo.entityID || rayPickInfo.overlayID) { this.intersectionDistance = rayPickInfo.distance; - this.searchSphereDistance = this.intersectionDistance; } }; @@ -2293,7 +2209,7 @@ function MyController(hand) { } if (isInEditMode()) { - this.searchIndicatorOn(rayPickInfo.searchRay); + this.updateLaserPointer(); if (this.triggerSmoothedGrab()) { if (!this.editTriggered){ if (rayPickInfo.entityID) { @@ -2326,7 +2242,7 @@ function MyController(hand) { } else { // potentialFarTriggerEntity = entity; } - this.otherGrabbingLineOff(); + this.laserPointerOff(); } else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) { if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { this.grabbedThingID = entity; @@ -2341,26 +2257,18 @@ function MyController(hand) { } else { // potentialFarGrabEntity = entity; } - this.otherGrabbingLineOff(); + this.laserPointerOff(); } else if (this.otherGrabbingUUID !== null) { if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { - var avatar = AvatarList.getAvatar(this.otherGrabbingUUID); - var IN_FRONT_OF_AVATAR = { x: 0, y: 0.2, z: 0.4 }; // Up from hips and in front of avatar. - var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR)); - var rayHitProps = entityPropertiesCache.getProps(rayPickInfo.entityID); - var finishPisition = Vec3.sum(rayHitProps.position, // Entity's centroid. - Vec3.multiplyQbyV(rayHitProps.rotation, - Vec3.multiplyVbyV(rayHitProps.dimensions, - Vec3.subtract(DEFAULT_REGISTRATION_POINT, rayHitProps.registrationPoint)))); - this.otherGrabbingLineOn(startPosition, finishPisition, COLORS_GRAB_DISTANCE_HOLD); + this.updateLaserPointer(); } else { - this.otherGrabbingLineOff(); + this.laserPointerOff(); } } else { - this.otherGrabbingLineOff(); + this.laserPointerOff(); } } else { - this.otherGrabbingLineOff(); + this.laserPointerOff(); } this.updateEquipHaptics(potentialEquipHotspot, handPosition); @@ -2372,7 +2280,7 @@ function MyController(hand) { } if (farGrabEnabled && farSearching) { - this.searchIndicatorOn(rayPickInfo.searchRay); + this.updateLaserPointer(); } Reticle.setVisible(false); }; @@ -2702,7 +2610,7 @@ function MyController(hand) { y: 0.0, z: objDistance }); - var change = Vec3.multiply(Vec3.subtract(before, after), HAND_HEAD_MIX_RATIO); + var change = Vec3.subtract(before, after) * (PICK_WITH_HAND_RAY ? 0.0 : 1.0); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } @@ -2711,11 +2619,7 @@ function MyController(hand) { this.maybeScale(grabbedProperties); // visualizations - var rayPickInfo = this.calcRayPickInfo(this.hand); - this.overlayLineOn(rayPickInfo.searchRay.origin, - Vec3.subtract(grabbedProperties.position, this.offsetPosition), - COLORS_GRAB_DISTANCE_HOLD, - this.grabbedThingID); + this.updateLaserPointer(); var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition)); @@ -2822,9 +2726,7 @@ function MyController(hand) { this.getOtherHandController().offsetPosition = Vec3.multiplyQbyV(controllerRotationDelta, this.getOtherHandController().offsetPosition); - var rayPickInfo = this.calcRayPickInfo(this.hand); - this.overlayLineOn(rayPickInfo.searchRay.origin, Vec3.subtract(grabbedProperties.position, this.offsetPosition), - COLORS_GRAB_DISTANCE_HOLD, this.grabbedThingID); + this.updateLaserPointer(); this.previousWorldControllerRotation = worldControllerRotation; }; @@ -2908,10 +2810,7 @@ function MyController(hand) { this.nearGrabbingEnter = function() { this.grabPointSphereOff(); - this.lineOff(); - this.overlayLineOff(); - this.searchSphereOff(); - this.otherGrabbingLineOff(); + this.laserPointerOff(); this.dropGestureReset(); this.clearEquipHaptics(); @@ -3415,28 +3314,18 @@ function MyController(hand) { return; } - var pickRay = { - origin: getControllerWorldLocation(this.handToController(), false).position, - direction: Quat.getUp(getControllerWorldLocation(this.handToController(), false).orientation) - }; - - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - var intersection = findRayIntersection(pickRay, true, [], [], true); - if (intersection.accurate || intersection.overlayID) { - this.lastPickTime = now; - if (intersection.entityID != this.grabbedThingID) { - this.callEntityMethodOnGrabbed("stopFarTrigger"); - this.grabbedThingID = null; - this.setState(STATE_OFF, "laser moved off of entity"); - return; - } - if (intersection.intersects) { - this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); - } - if (farGrabEnabled) { - this.searchIndicatorOn(pickRay); - } + var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer; + var intersection = LaserPointers.getPrevRayPickResult(laserPointerID); + if (intersection.type != RayPick.INTERSECTED_NONE) { + if (intersection.objectID != this.grabbedThingID) { + this.callEntityMethodOnGrabbed("stopFarTrigger"); + this.grabbedThingID = null; + this.setState(STATE_OFF, "laser moved off of entity"); + return; + } + this.intersectionDistance = intersection.distance; + if (farGrabEnabled) { + this.updateLaserPointer(); } } @@ -3444,14 +3333,7 @@ function MyController(hand) { }; this.offEnter = function() { - // Reuse the existing search distance if lasers were active since - // they will be shown in OFF state while in edit mode. - var existingSearchDistance = this.searchSphereDistance; this.release(); - - if (isInEditMode()) { - this.searchSphereDistance = existingSearchDistance; - } }; this.entityLaserTouchingEnter = function() { @@ -3558,7 +3440,7 @@ function MyController(hand) { this.intersectionDistance = intersectInfo.distance; if (this.state == STATE_ENTITY_LASER_TOUCHING) { - this.searchIndicatorOn(intersectInfo.searchRay); + this.updateLaserPointer(); } Reticle.setVisible(false); } else { @@ -3686,7 +3568,7 @@ function MyController(hand) { this.intersectionDistance = intersectInfo.distance; if (this.state == STATE_OVERLAY_LASER_TOUCHING) { - this.searchIndicatorOn(intersectInfo.searchRay); + this.updateLaserPointer(); } Reticle.setVisible(false); } else { @@ -3829,7 +3711,8 @@ function MyController(hand) { this.release(); this.grabPointSphereOff(); this.hideStylus(); - this.overlayLineOff(); + LaserPointers.removeLaserPointer(this.laserPointer); + LaserPointers.removeLaserPointer(this.headLaserPointer); }; this.thisHandIsParent = function(props) { @@ -3880,8 +3763,7 @@ function MyController(hand) { children = children.concat(Entities.getChildrenIDsOfJoint(AVATAR_SELF_ID, controllerCRJointIndex)); children.forEach(function(childID) { - if (childID !== _this.stylus && - childID !== _this.overlayLine) { + if (childID !== _this.stylus) { // we appear to be holding something and this script isn't in a state that would be holding something. // unhook it. if we previously took note of this entity's parent, put it back where it was. This // works around some problems that happen when more than one hand or avatar is passing something around. @@ -3995,6 +3877,15 @@ Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); Messages.subscribe('Hifi-Object-Manipulation'); Messages.subscribe('Hifi-Hand-Drop'); +var setBlacklist = function() { + if (USE_BLACKLIST) { + LaserPointers.setIgnoreEntities(leftController.laserPointer, blacklist); + LaserPointers.setIgnoreEntities(leftController.headLaserPointer, blacklist); + LaserPointers.setIgnoreEntities(rightController.laserPointer, blacklist); + LaserPointers.setIgnoreEntities(rightController.headLaserPointer, blacklist); + } +} + var handleHandMessages = function(channel, message, sender) { var data; if (sender === MyAvatar.sessionUUID) { @@ -4069,10 +3960,12 @@ var handleHandMessages = function(channel, message, sender) { if (action === 'add' && index === -1) { blacklist.push(id); + setBlacklist(); } if (action === 'remove') { if (index > -1) { blacklist.splice(index, 1); + setBlacklist(); } } diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index fc22d21089..f09cd07184 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -105,6 +105,9 @@ var teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd}, {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}]; +var DEFAULT_DISTANCE = 50; +var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; + function ThumbPad(hand) { this.hand = hand; var _thisPad = this; @@ -157,7 +160,8 @@ function Teleporter() { filter: RayPick.PICK_ENTITIES, faceAvatar: true, centerEndY: false, - renderStates: teleportRenderStates + renderStates: teleportRenderStates, + defaultRenderStates: teleportDefaultRenderStates }); this.teleportRayLeftInvisible = LaserPointers.createLaserPointer({ joint: "LeftHand", @@ -171,7 +175,8 @@ function Teleporter() { filter: RayPick.PICK_ENTITIES, faceAvatar: true, centerEndY: false, - renderStates: teleportRenderStates + renderStates: teleportRenderStates, + defaultRenderStates: teleportDefaultRenderStates }); this.teleportRayRightInvisible = LaserPointers.createLaserPointer({ joint: "RightHand", @@ -186,7 +191,8 @@ function Teleporter() { filter: RayPick.PICK_ENTITIES, faceAvatar: true, centerEndY: false, - renderStates: teleportRenderStates + renderStates: teleportRenderStates, + defaultRenderStates: teleportDefaultRenderStates }); this.teleportRayHeadInvisible = LaserPointers.createLaserPointer({ joint: "Avatar", @@ -331,7 +337,8 @@ function Teleporter() { } if (teleportLocationType === TARGET.NONE) { - this.setTeleportState(mode, "", ""); + // Use the cancel default state + this.setTeleportState(mode, "cancel", ""); } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.SURFACE) { @@ -516,13 +523,13 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -var setIgnoredEntities = function () { - LaserPointers.setIgnoredEntities(teleporter.teleportRayRightVisible, ignoredEntities); - LaserPointers.setIgnoredEntities(teleporter.teleportRayRightInvisible, ignoredEntities); - LaserPointers.setIgnoredEntities(teleporter.teleportRayLeftVisible, ignoredEntities); - LaserPointers.setIgnoredEntities(teleporter.teleportRayLeftInvisible, ignoredEntities); - LaserPointers.setIgnoredEntities(teleporter.teleportRayHeadVisible, ignoredEntities); - LaserPointers.setIgnoredEntities(teleporter.teleportRayHeadInvisible, ignoredEntities); +var setIgnoreEntities = function() { + LaserPointers.setIgnoreEntities(teleporter.teleportRayRightVisible, ignoredEntities); + LaserPointers.setIgnoreEntities(teleporter.teleportRayRightInvisible, ignoredEntities); + LaserPointers.setIgnoreEntities(teleporter.teleportRayLeftVisible, ignoredEntities); + LaserPointers.setIgnoreEntities(teleporter.teleportRayLeftInvisible, ignoredEntities); + LaserPointers.setIgnoreEntities(teleporter.teleportRayHeadVisible, ignoredEntities); + LaserPointers.setIgnoreEntities(teleporter.teleportRayHeadInvisible, ignoredEntities); } var isDisabled = false; @@ -543,12 +550,12 @@ var handleTeleportMessages = function(channel, message, sender) { } } else if (channel === 'Hifi-Teleport-Ignore-Add' && !Uuid.isNull(message) && ignoredEntities.indexOf(message) === -1) { ignoredEntities.push(message); - setIgnoredEntities(); + setIgnoreEntities(); } else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) { var removeIndex = ignoredEntities.indexOf(message); if (removeIndex > -1) { ignoredEntities.splice(removeIndex, 1); - setIgnoredEntities(); + setIgnoreEntities(); } } } From bacd839d432fb525610319e856ebc07c9f604f62 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 26 Jul 2017 18:57:19 -0700 Subject: [PATCH 37/95] Drag zip folder works --- interface/src/Application.cpp | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe75242c2f..d42453e191 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2748,7 +2748,7 @@ bool Application::importSVOFromURL(const QString& urlString) { bool Application::importFromZIP(const QString& filePath) { qDebug() << "A zip file has been dropped in: " << filePath; QUrl empty = ""; - qApp->getFileDownloadInterface()->runUnzip(filePath, empty, false, true); + qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true); return true; } @@ -6203,6 +6203,38 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBlocks) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). + qCDebug(interfaceapp) << "File about to be uploaded: " << filePath; + qCDebug(interfaceapp) << "Original zip folder: " << zipFile; + QString mapping; + QString path = filePath; + QString filename = filenameFromPath(filePath); + if (isBlocks) { + QString assetFolder = zipFile.section("/", -1); + assetFolder.remove(".zip"); + mapping = "/" + assetFolder + "/" + filenameFromPath(filename); + } + else { + path = QUrl(filePath).toLocalFile(); + filename = filenameFromPath(path); + mapping = "/" + filename; + } + + // Test repeated because possibly different code paths. + if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { + QString errorInfo = "You do not have permissions to write to the Asset Server."; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; + addAssetToWorldError(filename, errorInfo); + return; + } + + addAssetToWorldInfo(filename, "Adding " + mapping.mid(1) + " to the Asset Server."); + + addAssetToWorldWithNewMapping(path, mapping, 0); +} + +/**void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBlocks) { + // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). + qCDebug(interfaceapp) << "File about to be uploaded: " << filePath; qCDebug(interfaceapp) << "Original zip folder: " << zipFile; QString path = QUrl(filePath).toLocalFile(); @@ -6227,7 +6259,7 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBloc addAssetToWorldInfo(filename, "Adding " + mapping.mid(1) + " to the Asset Server."); addAssetToWorldWithNewMapping(path, mapping, 0); -} +}*/ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy) { auto request = DependencyManager::get()->createGetMappingRequest(mapping); From e3288a9004af5ce42d4538490ffd9fb7390426e8 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 27 Jul 2017 11:17:30 -0700 Subject: [PATCH 38/95] fix flicker, scissor warning, and handControllerGrab sphere size --- interface/src/raypick/LaserPointer.cpp | 14 +++++--------- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 2 ++ scripts/system/controllers/handControllerGrab.js | 3 ++- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 23adf5b532..ce25df340d 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -81,7 +81,7 @@ void LaserPointer::disable() { } void LaserPointer::setRenderState(const QString& state) { - if (!_currentRenderState.isEmpty()) { + if (!_currentRenderState.isEmpty() && state != _currentRenderState) { if (_renderStates.contains(_currentRenderState)) { disableRenderState(_renderStates[_currentRenderState]); } @@ -125,15 +125,12 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter glm::vec3 endVec; if (defaultState || !_lockEnd || type == IntersectionType::HUD) { endVec = pickRay.origin + pickRay.direction * distance; - } - else { + } else { if (type == IntersectionType::ENTITY) { endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; - } - else if (type == IntersectionType::OVERLAY) { + } else if (type == IntersectionType::OVERLAY) { endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); - } - else if (type == IntersectionType::AVATAR) { + } else if (type == IntersectionType::AVATAR) { endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); } } @@ -150,8 +147,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter QVariantMap endProps; if (_centerEndY) { endProps.insert("position", end); - } - else { + } else { glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value); endProps.insert("position", vec3toVariant(endVec + glm::vec3(0, 0.5f * dim.y, 0))); } diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 9b3fe10c55..4e8940fe59 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -628,6 +628,7 @@ void OpenGLDisplayPlugin::compositeLayers() { // Clear the depth framebuffer after drawing the scene so that the HUD elements can depth test against each other render([&](gpu::Batch& batch) { + batch.enableStereo(false); batch.setFramebuffer(_compositeFramebuffer); batch.clearDepthFramebuffer((float) UINT32_MAX); }); @@ -657,6 +658,7 @@ void OpenGLDisplayPlugin::compositeLayers() { // Clear the depth buffer again and draw the pointer last so it's on top of everything render([&](gpu::Batch& batch) { + batch.enableStereo(false); batch.setFramebuffer(_compositeFramebuffer); batch.clearDepthFramebuffer((float) UINT32_MAX); }); diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 79b00a3cae..7d76c2989f 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1410,7 +1410,8 @@ function MyController(hand) { this.updateLaserPointer = function() { var SEARCH_SPHERE_SIZE = 0.011; - var radius = 1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance; + var MIN_SPHERE_SIZE = 0.0005; + var radius = Math.max(1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance, MIN_SPHERE_SIZE); var dim = {x: radius, y: radius, z: radius}; var mode = "hold"; if (this.state !== STATE_DISTANCE_HOLDING && this.state !== STATE_DISTANCE_ROTATING) { From d4a7e9188a3dced093719f3ae05cab53c7bf63d8 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 27 Jul 2017 13:33:53 -0700 Subject: [PATCH 39/95] Removed extraneous print statements --- interface/src/Application.cpp | 38 +------------------ .../src/FileScriptingInterface.cpp | 1 - 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 941b6447ba..7b6b83fedd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2744,7 +2744,7 @@ bool Application::importSVOFromURL(const QString& urlString) { return true; } -// temporary zip handling for Emily, not set to auto-add +// temporary zip handling for Emily bool Application::importFromZIP(const QString& filePath) { qDebug() << "A zip file has been dropped in: " << filePath; QUrl empty = ""; @@ -6208,9 +6208,6 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBlocks) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). - - qCDebug(interfaceapp) << "File about to be uploaded: " << filePath; - qCDebug(interfaceapp) << "Original zip folder: " << zipFile; QString mapping; QString path = filePath; QString filename = filenameFromPath(filePath); @@ -6218,8 +6215,7 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBloc QString assetFolder = zipFile.section("/", -1); assetFolder.remove(".zip"); mapping = "/" + assetFolder + "/" + filenameFromPath(filename); - } - else { + } else { path = QUrl(filePath).toLocalFile(); filename = filenameFromPath(path); mapping = "/" + filename; @@ -6238,35 +6234,6 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBloc addAssetToWorldWithNewMapping(path, mapping, 0); } -/**void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBlocks) { - // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). - - qCDebug(interfaceapp) << "File about to be uploaded: " << filePath; - qCDebug(interfaceapp) << "Original zip folder: " << zipFile; - QString path = QUrl(filePath).toLocalFile(); - QString filename = filenameFromPath(path); - QString mapping; - if (isBlocks) { - QString assetFolder = zipFile.section("/", -1); - assetFolder.remove(".zip"); - mapping = "/" + assetFolder + "/" + filename; - } else { - mapping = "/" + filename; - } - - // Test repeated because possibly different code paths. - if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { - QString errorInfo = "You do not have permissions to write to the Asset Server."; - qWarning(interfaceapp) << "Error downloading model: " + errorInfo; - addAssetToWorldError(filename, errorInfo); - return; - } - - addAssetToWorldInfo(filename, "Adding " + mapping.mid(1) + " to the Asset Server."); - - addAssetToWorldWithNewMapping(path, mapping, 0); -}*/ - void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy) { auto request = DependencyManager::get()->createGetMappingRequest(mapping); @@ -6626,7 +6593,6 @@ void Application::onAssetToWorldMessageBoxClosed() { void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isBlocks) { if (autoAdd) { if (!unzipFile.isEmpty()) { - qCDebug(interfaceapp) << "My folder contents: " << unzipFile; for (int i = 0; i < unzipFile.length(); i++) { qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i); addAssetToWorld(unzipFile.at(i), zipFile, isBlocks); diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 5ba2868365..af1cf7994a 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -52,7 +52,6 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool } QStringList fileList = unzipFile(path, tempDir); - qCDebug(scriptengine) << "Unzipped file list: " << fileList; QString filename = QUrl::fromLocalFile(fileList.first()).toString(); if (filename != "") { From 3e2dbe58ec06a6add7b9e767e20ae3f81a4348c6 Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Thu, 27 Jul 2017 16:39:49 -0400 Subject: [PATCH 40/95] Style guide corrections --- libraries/entities/src/PolyLineEntityItem.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index c698e6d5dd..61d5dd22ee 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -158,22 +158,19 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { if (point.x > high.x){ high.x = point.x; - } - else if (point.x < low.x) { + } else if (point.x < low.x) { low.x = point.x; } if (point.y > high.y){ high.y = point.y; - } - else if (point.y < low.y) { + } else if (point.y < low.y) { low.y = point.y; } if (point.z > high.z){ high.z = point.z; - } - else if (point.z < low.z) { + } else if (point.z < low.z) { low.z = point.z; } } @@ -196,12 +193,10 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { glm::vec3 startPointInScaleSpace = point - low; glm::vec3 newRegistrationPoint = startPointInScaleSpace / result; EntityItem::setRegistrationPoint(newRegistrationPoint); - } - else { + } else { // if Polyline has only one or fewer points, use default dimension settings SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); - return; } } From fcaebda04c3c1618e1ab587b099fb9e91350b1f9 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Fri, 28 Jul 2017 10:21:03 -0700 Subject: [PATCH 41/95] troubleshooting Blocks injection --- scripts/system/html/js/marketplacesInject.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 0ee337a2ef..0fbd9a778e 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -96,11 +96,13 @@ function injectBlocksCode() { // Make space for marketplaces footer in Blocks pages. - $("head").append( - '' + /*$("body").append( + '
' + + '' + + '
' + );*/ + $("body").append( + 'style= "bottom: 135px" ' ); } From 25d4d4dc93fb4c099833299edbec932d702ae7a5 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Fri, 28 Jul 2017 15:13:24 -0700 Subject: [PATCH 42/95] Clara download working again, still can drag in Blocks zip --- interface/src/Application.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7c22e1bc55..3d784841d2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6224,14 +6224,12 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBloc // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString path = filePath; - QString filename = filenameFromPath(filePath); + QString filename = filenameFromPath(path); if (isBlocks) { QString assetFolder = zipFile.section("/", -1); assetFolder.remove(".zip"); - mapping = "/" + assetFolder + "/" + filenameFromPath(filename); + mapping = "/" + assetFolder + "/" + filename; } else { - path = QUrl(filePath).toLocalFile(); - filename = filenameFromPath(path); mapping = "/" + filename; } From c03c1c80e12909e45238d22dd99f0200f50e53f7 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 2 Aug 2017 10:51:40 -0700 Subject: [PATCH 43/95] Drag zip cleaned up, marketplaces stylized, back button fixed --- interface/src/Application.cpp | 12 +++++----- interface/src/Application.h | 2 -- scripts/system/html/js/marketplacesInject.js | 16 +++++++++---- scripts/system/html/marketplaces.html | 24 +++++++++++--------- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4a4b6423b9..467614c8a8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -229,8 +229,6 @@ static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString WEB_VIEW_TAG = "noDownload=true"; - -// temporary zip handling for Emily static const QString ZIP_EXTENSION = ".zip"; static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; @@ -264,8 +262,6 @@ const QHash Application::_acceptedExtensi { JSON_EXTENSION, &Application::importJSONFromURL }, { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, - - // temporary zip handling for Emily { ZIP_EXTENSION, &Application::importFromZIP } }; @@ -2759,7 +2755,6 @@ bool Application::importSVOFromURL(const QString& urlString) { return true; } -// temporary zip handling for Emily bool Application::importFromZIP(const QString& filePath) { qDebug() << "A zip file has been dropped in: " << filePath; QUrl empty = ""; @@ -6315,7 +6310,12 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { - addAssetToWorldAddEntity(filePath, mapping); + // to prevent files that aren't models from being loaded into world automatically + if (filePath.endsWith(".obj") || filePath.endsWith(".fbx")) { + addAssetToWorldAddEntity(filePath, mapping); + } else { + addAssetToWorldInfoDone(filenameFromPath(filePath)); + } } request->deleteLater(); }); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f835d5525..9546c275dc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -481,8 +481,6 @@ private: bool importJSONFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString); - - // temporary zip handling for Emily bool importFromZIP(const QString& filePath); bool nearbyEntitiesAreReadyForPhysics(); diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 0fbd9a778e..92fa869242 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -65,7 +65,10 @@ // Footer actions. $("#back-button").on("click", function () { - window.history.back(); + if (window.history.state != null) window.history.back(); + // to fix back button issue when in directory + //else window.location = "http://www.highfidelity.com/marketplace"; + else window.location = "https://metaverse.highfidelity.com/marketplace?"; }); $("#all-markets").on("click", function () { EventBridge.emitWebEvent(GOTO_DIRECTORY); @@ -79,9 +82,11 @@ letUsKnow.replaceWith(letUsKnow.html()); // Add button links. + + /* Blocks not yet implemented $('#exploreBlocksMarketplace').on('click', function () { window.location = "https://vr.google.com/objects"; - }); + });*/ $('#exploreClaraMarketplace').on('click', function () { window.location = "https://clara.io/library?gameCheck=true&public=true"; }); @@ -102,7 +107,7 @@ '
' );*/ $("body").append( - 'style= "bottom: 135px" ' + '

hello

' ); } @@ -345,6 +350,7 @@ if (location.href.indexOf("google.com/") !== -1) { pageType = BLOCKS; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } + //if (pageType != BLOCKS) injectCommonCode(pageType === DIRECTORY); switch (pageType) { case DIRECTORY: @@ -354,7 +360,9 @@ injectHiFiCode(); break; case BLOCKS: - injectBlocksCode(); + console.log("in Blocks"); + //injectBlocksCode(); + console.log("blocks injection"); break; case CLARA: injectClaraCode(); diff --git a/scripts/system/html/marketplaces.html b/scripts/system/html/marketplaces.html index 8c5fe15429..11c9e208ca 100644 --- a/scripts/system/html/marketplaces.html +++ b/scripts/system/html/marketplaces.html @@ -25,24 +25,26 @@

This is the default High Fidelity marketplace. Viewing and downloading content from here is fully supported in Interface.

-
- -
-
+
+ +
+
+
@@ -53,9 +55,9 @@
  • Create an account here or log in as an existing user.
  • Choose a model from the list and click “Download to High Fidelity”.
  • -
    - -
    +
    +
    +
    From 310a0eeecc54ab607e573506f618ba5008065eb8 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 2 Aug 2017 12:24:14 -0700 Subject: [PATCH 44/95] Renamed isBlocks to isZip, added debug print for non-entity files --- interface/src/Application.cpp | 9 +++++---- interface/src/Application.h | 4 ++-- libraries/script-engine/src/FileScriptingInterface.cpp | 6 +++--- libraries/script-engine/src/FileScriptingInterface.h | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 467614c8a8..c19635ef34 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6218,12 +6218,12 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { addAssetToWorldError(filename, "Couldn't unzip file " + filename + "."); } -void Application::addAssetToWorld(QString filePath, QString zipFile, bool isBlocks) { +void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString path = filePath; QString filename = filenameFromPath(path); - if (isBlocks) { + if (isZip) { QString assetFolder = zipFile.section("/", -1); assetFolder.remove(".zip"); mapping = "/" + assetFolder + "/" + filename; @@ -6314,6 +6314,7 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q if (filePath.endsWith(".obj") || filePath.endsWith(".fbx")) { addAssetToWorldAddEntity(filePath, mapping); } else { + qCDebug(interfaceapp) << "Zipped contents are not valid entity files"; addAssetToWorldInfoDone(filenameFromPath(filePath)); } } @@ -6605,12 +6606,12 @@ void Application::onAssetToWorldMessageBoxClosed() { } -void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isBlocks) { +void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip) { if (autoAdd) { if (!unzipFile.isEmpty()) { for (int i = 0; i < unzipFile.length(); i++) { qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i); - addAssetToWorld(unzipFile.at(i), zipFile, isBlocks); + addAssetToWorld(unzipFile.at(i), zipFile, isZip); } } else { addAssetToWorldUnzipFailure(zipFile); diff --git a/interface/src/Application.h b/interface/src/Application.h index 9546c275dc..975767d4fb 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -332,14 +332,14 @@ public slots: // FIXME: Move addAssetToWorld* methods to own class? void addAssetToWorldFromURL(QString url); void addAssetToWorldFromURLRequestFinished(); - void addAssetToWorld(QString filePath, QString zipFile, bool isBlocks); + void addAssetToWorld(QString filePath, QString zipFile, bool isZip); void addAssetToWorldUnzipFailure(QString filePath); void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy); void addAssetToWorldUpload(QString filePath, QString mapping); void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash); void addAssetToWorldAddEntity(QString filePath, QString mapping); - void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isBlocks); + void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip); FileScriptingInterface* getFileDownloadInterface() { return _fileDownload; } diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index af1cf7994a..0baf3034e8 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -32,12 +32,12 @@ FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent // nothing for now } -void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isBlocks) { +void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isZip) { qCDebug(scriptengine) << "Url that was downloaded: " + url.toString(); qCDebug(scriptengine) << "Path where download is saved: " + path; QString fileName = "/" + path.section("/", -1); QString tempDir = path; - if (!isBlocks) { + if (!isZip) { tempDir.remove(fileName); } else { QTemporaryDir blocks; @@ -60,7 +60,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool else { qCDebug(scriptengine) << "Unzip failed"; } - emit unzipResult(path, fileList, autoAdd, isBlocks); + emit unzipResult(path, fileList, autoAdd, isZip); } diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h index 806fa7fd9b..4069e7cc78 100644 --- a/libraries/script-engine/src/FileScriptingInterface.h +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -24,11 +24,11 @@ public: public slots: QString convertUrlToPath(QUrl url); - void runUnzip(QString path, QUrl url, bool autoAdd, bool isBlocks); + void runUnzip(QString path, QUrl url, bool autoAdd, bool isZip); QString getTempDir(); signals: - void unzipResult(QString zipFile, QStringList unzipFile, bool autoAdd, bool isBlocks); + void unzipResult(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip); private: bool isTempDir(QString tempDir); From 8b1c24e636f38793ee7dca1442e55ee4f458a940 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 4 Aug 2017 18:26:11 -0700 Subject: [PATCH 45/95] added setLockEndUUID, update handControllerGrab and grab --- interface/src/raypick/LaserPointer.cpp | 35 +++++++++++++++---- interface/src/raypick/LaserPointer.h | 3 ++ interface/src/raypick/LaserPointerManager.cpp | 10 +++++- interface/src/raypick/LaserPointerManager.h | 2 ++ .../raypick/LaserPointerScriptingInterface.h | 2 ++ scripts/system/controllers/grab.js | 2 +- .../system/controllers/handControllerGrab.js | 5 +++ 7 files changed, 50 insertions(+), 9 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index ce25df340d..342d7b37de 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -123,15 +123,36 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter qApp->getOverlays().editOverlay(renderState.getStartID(), startProps); } glm::vec3 endVec; - if (defaultState || !_lockEnd || type == IntersectionType::HUD) { + if (((defaultState || !_lockEnd) && _objectLockEnd.first.isNull()) || type == IntersectionType::HUD) { endVec = pickRay.origin + pickRay.direction * distance; } else { - if (type == IntersectionType::ENTITY) { - endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; - } else if (type == IntersectionType::OVERLAY) { - endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); - } else if (type == IntersectionType::AVATAR) { - endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); + if (!_objectLockEnd.first.isNull()) { + glm::vec3 pos; + glm::quat rot; + glm::vec3 dim; + glm::vec3 registrationPoint; + if (_objectLockEnd.second) { + pos = vec3FromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "position").value); + rot = quatFromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "rotation").value); + dim = vec3FromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "dimensions").value); + registrationPoint = glm::vec3(0.5f); + } else { + EntityItemProperties props = DependencyManager::get()->getEntityProperties(_objectLockEnd.first); + pos = props.getPosition(); + rot = props.getRotation(); + dim = props.getDimensions(); + registrationPoint = props.getRegistrationPoint(); + } + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint)); + } else { + if (type == IntersectionType::ENTITY) { + endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; + } else if (type == IntersectionType::OVERLAY) { + endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); + } else if (type == IntersectionType::AVATAR) { + endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); + } } } QVariant end = vec3toVariant(endVec); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 34d9ee50df..6f70268b8c 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -68,6 +68,8 @@ public: void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(_rayPickUID, ignoreAvatars); } void setIncludeAvatars(const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(_rayPickUID, includeAvatars); } + void setLockEndUUID(QUuid objectID, const bool isOverlay) { _objectLockEnd = QPair(objectID, isOverlay); } + void update(); private: @@ -78,6 +80,7 @@ private: bool _faceAvatar; bool _centerEndY; bool _lockEnd; + QPair _objectLockEnd { QPair(QUuid(), false)}; QUuid _rayPickUID; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index b05f56fa53..b852416463 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -143,4 +143,12 @@ void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& inclu QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeAvatars(includeAvatars); } -} \ No newline at end of file +} + +void LaserPointerManager::setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { + QReadLocker lock(&_containsLock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setLockEndUUID(objectID, isOverlay); + } +} diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index db035b197f..dc9790af4e 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -41,6 +41,8 @@ public: void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars); void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars); + void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay); + void update(); private: diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index a6b61446a7..f28a09dbbc 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -37,6 +37,8 @@ public slots: Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(uid, ignoreAvatars); } Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(uid, includeAvatars); } + Q_INVOKABLE void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + private: const RenderState buildRenderState(const QVariantMap & propMap); diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index a3473df7e3..1651877407 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -266,7 +266,6 @@ function Grabber() { this.mouseRayEntities = LaserPointers.createLaserPointer({ joint: "Mouse", filter: RayPick.PICK_ENTITIES, - lockEnd: true, faceAvatar: true, enabled: true }); @@ -341,6 +340,7 @@ Grabber.prototype.pressEvent = function(event) { } LaserPointers.setRenderState(this.mouseRayEntities, "grabbed"); + LaserPointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false); mouse.startDrag(event); diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 855a50e009..dccf8e890b 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1438,6 +1438,11 @@ function MyController(hand) { } LaserPointers.enableLaserPointer(laserPointerID); LaserPointers.setRenderState(laserPointerID, mode); + if (this.state === STATE_DISTANCE_HOLDING || this.state === STATE_DISTANCE_ROTATING) { + LaserPointers.setLockEndUUID(laserPointerID, this.grabbedThingID, this.grabbedIsOverlay); + } else { + LaserPointers.setLockEndUUID(laserPointerID, null, false); + } }; this.laserPointerOff = function() { From 42147640e25d2c689531b2f041c0bd31a455df78 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 7 Aug 2017 14:18:56 -0700 Subject: [PATCH 46/95] remove LaserPointerManager as a dependency --- interface/src/Application.cpp | 3 +-- interface/src/Application.h | 5 ++++ interface/src/raypick/LaserPointerManager.h | 4 +-- .../LaserPointerScriptingInterface.cpp | 4 +-- .../raypick/LaserPointerScriptingInterface.h | 25 ++++++++++--------- interface/src/raypick/RayPickManager.cpp | 2 -- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bc2e2f8ec8..5444968e67 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -602,7 +602,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); return previousSessionCrashed; @@ -5049,7 +5048,7 @@ void Application::update(float deltaTime) { { PROFILE_RANGE(app, "LaserPointerManager"); - DependencyManager::get()->update(); + _laserPointerManager.update(); } // Update _viewFrustum with latest camera and view frustum data... diff --git a/interface/src/Application.h b/interface/src/Application.h index f8eb393f9e..83ae0b036a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -70,6 +70,7 @@ #include "ui/OverlayConductor.h" #include "ui/overlays/Overlays.h" #include "UndoStackScriptingInterface.h" +#include "raypick/LaserPointerManager.h" #include #include @@ -300,6 +301,8 @@ public: QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; } bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } + LaserPointerManager& getLaserPointerManager() { return _laserPointerManager; } + signals: void svoImportRequested(const QString& url); @@ -697,5 +700,7 @@ private: QUrl _avatarOverrideUrl; bool _saveAvatarOverrideUrl { false }; + LaserPointerManager _laserPointerManager; + }; #endif // hifi_Application_h diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index dc9790af4e..002b8ce38e 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -17,12 +17,10 @@ #include #include "LaserPointer.h" -#include "DependencyManager.h" class RayPickResult; -class LaserPointerManager : public Dependency { - SINGLETON_DEPENDENCY +class LaserPointerManager { public: QUuid createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 9bda37f26f..78a62d0ed8 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -69,7 +69,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert } } - return DependencyManager::get()->createLaserPointer(propertyMap, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); + return qApp->getLaserPointerManager().createLaserPointer(propertyMap, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); } void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& renderState, const QVariant& properties) { @@ -90,7 +90,7 @@ void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& r endProps = propMap["end"]; } - DependencyManager::get()->editRenderState(uid, renderState, startProps, pathProps, endProps); + qApp->getLaserPointerManager().editRenderState(uid, renderState, startProps, pathProps, endProps); } const RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index f28a09dbbc..70d2e9a1fd 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -16,6 +16,7 @@ #include "LaserPointerManager.h" #include "RegisteredMetaTypes.h" #include "DependencyManager.h" +#include "Application.h" class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -23,21 +24,21 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { public slots: Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties); - Q_INVOKABLE void enableLaserPointer(QUuid uid) { DependencyManager::get()->enableLaserPointer(uid); } - Q_INVOKABLE void disableLaserPointer(QUuid uid) { DependencyManager::get()->disableLaserPointer(uid); } - Q_INVOKABLE void removeLaserPointer(QUuid uid) { DependencyManager::get()->removeLaserPointer(uid); } + Q_INVOKABLE void enableLaserPointer(QUuid uid) { qApp->getLaserPointerManager().enableLaserPointer(uid); } + Q_INVOKABLE void disableLaserPointer(QUuid uid) { qApp->getLaserPointerManager().disableLaserPointer(uid); } + Q_INVOKABLE void removeLaserPointer(QUuid uid) { qApp->getLaserPointerManager().removeLaserPointer(uid); } Q_INVOKABLE void editRenderState(QUuid uid, const QString& renderState, const QVariant& properties); - Q_INVOKABLE void setRenderState(QUuid uid, const QString& renderState) { DependencyManager::get()->setRenderState(uid, renderState); } - Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return DependencyManager::get()->getPrevRayPickResult(uid); } + Q_INVOKABLE void setRenderState(QUuid uid, const QString& renderState) { qApp->getLaserPointerManager().setRenderState(uid, renderState); } + Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); } - Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(uid, ignoreEntities); } - Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(uid, includeEntities); } - Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(uid, ignoreOverlays); } - Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(uid, includeOverlays); } - Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(uid, ignoreAvatars); } - Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(uid, includeAvatars); } + Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); } + Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { qApp->getLaserPointerManager().setIncludeEntities(uid, includeEntities); } + Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { qApp->getLaserPointerManager().setIgnoreOverlays(uid, ignoreOverlays); } + Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { qApp->getLaserPointerManager().setIncludeOverlays(uid, includeOverlays); } + Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { qApp->getLaserPointerManager().setIgnoreAvatars(uid, ignoreAvatars); } + Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { qApp->getLaserPointerManager().setIncludeAvatars(uid, includeAvatars); } - Q_INVOKABLE void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); } private: const RenderState buildRenderState(const QVariantMap & propMap); diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 0814466e4b..e9698f4a17 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -59,8 +59,6 @@ void RayPickManager::update() { continue; } - // TODO: - // get rid of this and make PickRay hashable QPair rayKey = QPair(ray.origin, ray.direction); RayPickResult res; From 6d253fcc5f24cc0f60be8852cda7bbae339bc741 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 7 Aug 2017 18:37:55 -0700 Subject: [PATCH 47/95] cleaning up --- interface/src/raypick/LaserPointer.cpp | 33 +++++++++---------- interface/src/raypick/LaserPointer.h | 2 ++ interface/src/raypick/LaserPointerManager.cpp | 3 +- interface/src/raypick/RayPickManager.cpp | 2 +- interface/src/raypick/RayPickManager.h | 2 ++ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 342d7b37de..2aeda6c800 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -38,27 +38,12 @@ LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash()->removeRayPick(_rayPickUID); + for (RenderState& renderState : _renderStates) { - if (!renderState.getStartID().isNull()) { - qApp->getOverlays().deleteOverlay(renderState.getStartID()); - } - if (!renderState.getPathID().isNull()) { - qApp->getOverlays().deleteOverlay(renderState.getPathID()); - } - if (!renderState.getEndID().isNull()) { - qApp->getOverlays().deleteOverlay(renderState.getEndID()); - } + renderState.deleteOverlays(); } for (QPair& renderState : _defaultRenderStates) { - if (!renderState.second.getStartID().isNull()) { - qApp->getOverlays().deleteOverlay(renderState.second.getStartID()); - } - if (!renderState.second.getPathID().isNull()) { - qApp->getOverlays().deleteOverlay(renderState.second.getPathID()); - } - if (!renderState.second.getEndID().isNull()) { - qApp->getOverlays().deleteOverlay(renderState.second.getEndID()); - } + renderState.second.deleteOverlays(); } } @@ -229,4 +214,16 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons if (!_endID.isNull()) { _endIgnoreRays = qApp->getOverlays().getOverlay(_endID)->getProperty("ignoreRayIntersection").toBool(); } +} + +void RenderState::deleteOverlays() { + if (!_startID.isNull()) { + qApp->getOverlays().deleteOverlay(_startID); + } + if (!_pathID.isNull()) { + qApp->getOverlays().deleteOverlay(_pathID); + } + if (!_endID.isNull()) { + qApp->getOverlays().deleteOverlay(_endID); + } } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 6f70268b8c..da29aee3f1 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -36,6 +36,8 @@ public: const bool& doesPathIgnoreRays() const { return _pathIgnoreRays; } const bool& doesEndIgnoreRays() const { return _endIgnoreRays; } + void deleteOverlays(); + private: OverlayID _startID; OverlayID _pathID; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index b852416463..33f292b255 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -9,13 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "LaserPointerManager.h" -#include "LaserPointer.h" #include "RayPick.h" QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); - if (laserPointer->getRayUID() != 0) { + if (!laserPointer->getRayUID().isNull()) { QWriteLocker lock(&_addLock); QUuid id = QUuid::createUuid(); _laserPointersToAdd.enqueue(QPair>(id, laserPointer)); diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index e9698f4a17..f7f22a66bb 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -194,7 +194,7 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { return id; } - return 0; + return QUuid(); } void RayPickManager::removeRayPick(const QUuid uid) { diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 27428ab43c..592541e7cf 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -30,11 +30,13 @@ enum RayPickMask { PICK_AVATARS = 1 << 2, PICK_HUD = 1 << 3, + // NOT YET IMPLEMENTED PICK_BOUNDING_BOX = 1 << 4, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) PICK_INCLUDE_INVISIBLE = 1 << 5, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements PICK_INCLUDE_NONCOLLIDABLE = 1 << 6, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements + // NOT YET IMPLEMENTED PICK_ALL_INTERSECTIONS = 1 << 7 // if not set, returns closest intersection, otherwise, returns list of all intersections }; From 684001a756e65c0e9d033360ecca2106c9859ec1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 8 Aug 2017 11:11:19 -0700 Subject: [PATCH 48/95] workaround deadlock in editRenderState --- interface/src/raypick/LaserPointer.cpp | 21 ++++++--------------- interface/src/raypick/LaserPointer.h | 6 ++---- scripts/system/controllers/grab.js | 4 +++- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 2aeda6c800..a59a85d700 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -78,24 +78,15 @@ void LaserPointer::setRenderState(const QString& state) { } void LaserPointer::editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { - _renderStates[state].setStartID(updateRenderStateOverlay(_renderStates[state].getStartID(), startProps)); - _renderStates[state].setPathID(updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps)); - _renderStates[state].setEndID(updateRenderStateOverlay(_renderStates[state].getEndID(), endProps)); + updateRenderStateOverlay(_renderStates[state].getStartID(), startProps); + updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps); + updateRenderStateOverlay(_renderStates[state].getEndID(), endProps); } -OverlayID LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& props) { - if (props.isValid()) { - if (!id.isNull()) { - qApp->getOverlays().editOverlay(id, props); - return id; - } else { - QVariantMap propsMap = props.toMap(); - if (propsMap["type"].isValid()) { - return qApp->getOverlays().addOverlay(propsMap["type"].toString(), props); - } - } +void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& props) { + if (!id.isNull() && props.isValid()) { + qApp->getOverlays().editOverlay(id, props); } - return OverlayID(); } void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState) { diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index da29aee3f1..946b01d3ba 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -29,9 +29,6 @@ public: const OverlayID& getStartID() const { return _startID; } const OverlayID& getPathID() const { return _pathID; } const OverlayID& getEndID() const { return _endID; } - void setStartID(const OverlayID& startID) { _startID = startID; } - void setPathID(const OverlayID& pathID) { _pathID = pathID; } - void setEndID(const OverlayID& endID) { _endID = endID; } const bool& doesStartIgnoreRays() const { return _startIgnoreRays; } const bool& doesPathIgnoreRays() const { return _pathIgnoreRays; } const bool& doesEndIgnoreRays() const { return _endIgnoreRays; } @@ -61,6 +58,7 @@ public: const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } void setRenderState(const QString& state); + // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. void editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(_rayPickUID, ignoreEntities); } @@ -86,7 +84,7 @@ private: QUuid _rayPickUID; - OverlayID updateRenderStateOverlay(const OverlayID& id, const QVariant& props); + void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState); void disableRenderState(const RenderState& renderState); }; diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 1651877407..2844940d2b 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -263,11 +263,13 @@ function Grabber() { enabled: true }); RayPick.setIncludeOverlays(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + var renderStates = [{name: "grabbed", end: beacon}]; this.mouseRayEntities = LaserPointers.createLaserPointer({ joint: "Mouse", filter: RayPick.PICK_ENTITIES, faceAvatar: true, - enabled: true + enabled: true, + renderStates: renderStates }); } From 3645bf04b6d5a178f2d5140f2a3e440ae542dedc Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 8 Aug 2017 18:10:53 -0700 Subject: [PATCH 49/95] possibly fix most annoying crash --- interface/src/avatar/AvatarManager.cpp | 16 +++++--- interface/src/avatar/AvatarManager.h | 3 ++ interface/src/raypick/LaserPointer.cpp | 6 +-- interface/src/raypick/RayPick.h | 39 ++++++++++--------- interface/src/ui/overlays/Overlays.cpp | 18 ++++----- interface/src/ui/overlays/Overlays.h | 10 +++-- .../entities/src/EntityScriptingInterface.cpp | 12 ++++-- .../entities/src/EntityScriptingInterface.h | 5 +++ 8 files changed, 67 insertions(+), 42 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bd545c64e0..35039f168c 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -476,19 +476,25 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude, const QScriptValue& avatarIdsToDiscard) { + QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); + QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); + + return findRayIntersection(ray, avatarsToInclude, avatarsToDiscard); +} + +RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard) { RayToAvatarIntersectionResult result; if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersection", Q_RETURN_ARG(RayToAvatarIntersectionResult, result), Q_ARG(const PickRay&, ray), - Q_ARG(const QScriptValue&, avatarIdsToInclude), - Q_ARG(const QScriptValue&, avatarIdsToDiscard)); + Q_ARG(const QVector&, avatarsToInclude), + Q_ARG(const QVector&, avatarsToDiscard)); return result; } - QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); - QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); - glm::vec3 normDirection = glm::normalize(ray.direction); for (auto avatarData : _avatarHash) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 30801807d6..c21214484b 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -73,6 +73,9 @@ public: Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToDiscard = QScriptValue()); + Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard); // TODO: remove this HACK once we settle on optimal default sort coefficients Q_INVOKABLE float getAvatarSortCoefficient(const QString& name); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index a59a85d700..9dc1bdd72e 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -197,13 +197,13 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons _startID(startID), _pathID(pathID), _endID(endID) { if (!_startID.isNull()) { - _startIgnoreRays = qApp->getOverlays().getOverlay(_startID)->getProperty("ignoreRayIntersection").toBool(); + _startIgnoreRays = qApp->getOverlays().getProperty(_startID, "ignoreRayIntersection").value.toBool(); } if (!_pathID.isNull()) { - _pathIgnoreRays = qApp->getOverlays().getOverlay(_pathID)->getProperty("ignoreRayIntersection").toBool(); + _pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool(); } if (!_endID.isNull()) { - _endIgnoreRays = qApp->getOverlays().getOverlay(_endID)->getProperty("ignoreRayIntersection").toBool(); + _endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignoreRayIntersection").value.toBool(); } } diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index ca9660729a..48841b9518 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -14,6 +14,9 @@ #include #include "RegisteredMetaTypes.h" +#include "EntityItemID.h" +#include "ui/overlays/Overlay.h" + class RayPick { public: @@ -31,18 +34,18 @@ public: void setRayPickResult(const RayPickResult& rayPickResult) { _prevResult = rayPickResult; } - const QScriptValue& getIgnoreEntites() { return _ignoreEntities; } - const QScriptValue& getIncludeEntites() { return _includeEntities; } - const QScriptValue& getIgnoreOverlays() { return _ignoreOverlays; } - const QScriptValue& getIncludeOverlays() { return _includeOverlays; } - const QScriptValue& getIgnoreAvatars() { return _ignoreAvatars; } - const QScriptValue& getIncludeAvatars() { return _includeAvatars; } - void setIgnoreEntities(const QScriptValue& ignoreEntities) { _ignoreEntities = ignoreEntities; } - void setIncludeEntities(const QScriptValue& includeEntities) { _includeEntities = includeEntities; } - void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { _ignoreOverlays = ignoreOverlays; } - void setIncludeOverlays(const QScriptValue& includeOverlays) { _includeOverlays = includeOverlays; } - void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { _ignoreAvatars = ignoreAvatars; } - void setIncludeAvatars(const QScriptValue& includeAvatars) { _includeAvatars = includeAvatars; } + const QVector& getIgnoreEntites() { return _ignoreEntities; } + const QVector& getIncludeEntites() { return _includeEntities; } + const QVector& getIgnoreOverlays() { return _ignoreOverlays; } + const QVector& getIncludeOverlays() { return _includeOverlays; } + const QVector& getIgnoreAvatars() { return _ignoreAvatars; } + const QVector& getIncludeAvatars() { return _includeAvatars; } + void setIgnoreEntities(const QScriptValue& ignoreEntities) { _ignoreEntities = qVectorEntityItemIDFromScriptValue(ignoreEntities); } + void setIncludeEntities(const QScriptValue& includeEntities) { _includeEntities = qVectorEntityItemIDFromScriptValue(includeEntities); } + void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { _ignoreOverlays = qVectorOverlayIDFromScriptValue(ignoreOverlays); } + void setIncludeOverlays(const QScriptValue& includeOverlays) { _includeOverlays = qVectorOverlayIDFromScriptValue(includeOverlays); } + void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { _ignoreAvatars = qVectorEntityItemIDFromScriptValue(ignoreAvatars); } + void setIncludeAvatars(const QScriptValue& includeAvatars) { _includeAvatars = qVectorEntityItemIDFromScriptValue(includeAvatars); } private: uint16_t _filter; @@ -50,12 +53,12 @@ private: bool _enabled; RayPickResult _prevResult; - QScriptValue _ignoreEntities; - QScriptValue _includeEntities; - QScriptValue _ignoreOverlays; - QScriptValue _includeOverlays; - QScriptValue _ignoreAvatars; - QScriptValue _includeAvatars; + QVector _ignoreEntities; + QVector _includeEntities; + QVector _ignoreOverlays; + QVector _includeOverlays; + QVector _ignoreAvatars; + QVector _includeAvatars; }; #endif // hifi_RayPick_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5ec669af15..04ee205ba6 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -534,15 +534,15 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, const QVector overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude); const QVector overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard); - return findRayIntersectionInternal(ray, precisionPicking, - overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly); + return findRayIntersection(ray, precisionPicking, + overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly); } -RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToDiscard, - bool visibleOnly, bool collidableOnly) { +RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly, bool collidableOnly) { float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; @@ -908,21 +908,21 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRa // first priority is tablet screen overlaysToInclude << qApp->getTabletScreenID(); - rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard); + rayPickResult = findRayIntersection(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } // then tablet home button overlaysToInclude.clear(); overlaysToInclude << qApp->getTabletHomeButtonID(); - rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard); + rayPickResult = findRayIntersection(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } // then tablet frame overlaysToInclude.clear(); overlaysToInclude << OverlayID(qApp->getTabletFrameID()); - rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard); + rayPickResult = findRayIntersection(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index f1042eb55b..9db6375e84 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -216,6 +216,12 @@ public slots: bool visibleOnly = false, bool collidableOnly = false); + // Same as above but with QVectors + RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly = false, bool collidableOnly = false); + /**jsdoc * Return a list of 3d overlays with bounding boxes that touch the given sphere * @@ -350,10 +356,6 @@ private: OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID }; - Q_INVOKABLE RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToDiscard, - bool visibleOnly = false, bool collidableOnly = false); RayToOverlayIntersectionResult findRayIntersectionForMouseEvent(PickRay ray); }; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index e21c9581e1..1eb9ef8462 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -679,11 +679,17 @@ QVector EntityScriptingInterface::findEntitiesByType(const QString entity RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) { - PROFILE_RANGE(script_entities, __FUNCTION__); - QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); - return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard, visibleOnly, collidableOnly); + + return findRayIntersection(ray, precisionPicking, entitiesToInclude, entitiesToDiscard, visibleOnly, collidableOnly); +} + +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, + const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly); } // FIXME - we should remove this API and encourage all users to use findRayIntersection() instead. We've changed diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 575528fa78..fc5053bdd6 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -229,6 +229,11 @@ public slots: const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue(), bool visibleOnly = false, bool collidableOnly = false); + /// Same as above but with QVectors + Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking, + const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, + bool visibleOnly, bool collidableOnly); + /// If the scripting context has visible entities, this will determine a ray intersection, and will block in /// order to return an accurate result Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue()); From d599753771c38df1d617e9e4c435c1bb979f837c Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 8 Aug 2017 18:43:35 -0700 Subject: [PATCH 50/95] Started blocks download catch, fixed a debug typo --- interface/src/Application.cpp | 19 ++++++++++------ .../src/FileScriptingInterface.cpp | 22 ++++++++++++++++--- .../src/FileScriptingInterface.h | 1 + scripts/system/html/js/marketplacesInject.js | 8 +++---- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e5fb9949db..c887007fae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2774,6 +2774,18 @@ bool Application::importSVOFromURL(const QString& urlString) { return true; } +bool Application::importFromZIP(const QString& filePath) { + qDebug() << "A zip file has been dropped in: " << filePath; + QUrl empty; + // handle Blocks download from Marketplace + if (filePath.contains("vr.google.com/downloads")) { + qApp->getFileDownloadInterface()->runUnzip("", filePath, true, true); + } else { + qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true); + } + return true; +} + void Application::onPresent(quint32 frameCount) { if (shouldPaint()) { postEvent(this, new QEvent(static_cast(Idle)), Qt::HighEventPriority); @@ -2781,13 +2793,6 @@ void Application::onPresent(quint32 frameCount) { } } -bool Application::importFromZIP(const QString& filePath) { - qDebug() << "A zip file has been dropped in: " << filePath; - QUrl empty; - qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true); - return true; -} - bool _renderRequested { false }; bool Application::event(QEvent* event) { diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 5eaaea86a9..ba1e9bcddf 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -34,6 +34,10 @@ FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isZip) { qCDebug(scriptengine) << "Url that was downloaded: " + url.toString(); + if ((url.toString()).contains("vr.google.com/downloads")) { + + path = downloadBlocksZip(url); + } qCDebug(scriptengine) << "Path where download is saved: " + path; QString fileName = "/" + path.section("/", -1); QString tempDir = path; @@ -52,10 +56,10 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool } QStringList fileList = unzipFile(path, tempDir); - QString filename = QUrl::fromLocalFile(fileList.first()).toString(); + //QString filename = QUrl::fromLocalFile(fileList.first()).toString(); - if (filename != "") { - qCDebug(scriptengine) << "File to upload: " + filename; + if (!fileList.isEmpty()) { + qCDebug(scriptengine) << "File to upload: " + fileList.first(); } else { qCDebug(scriptengine) << "Unzip failed"; @@ -111,6 +115,18 @@ QString FileScriptingInterface::convertUrlToPath(QUrl url) { return newUrl; } +// handles a download from Blocks in the marketplace +QString FileScriptingInterface::downloadBlocksZip(QUrl url) { + qCDebug(scriptengine) << "Made it to the download blocks! " << url.toString(); + + /*auto request = DependencyManager::get()->createResourceRequest(nullptr, url); + connect(request, &ResourceRequest::finished, this, [this, url] { + unzipFile(url, ""); // so intellisense isn't mad + }); + request->send();*/ + return url.toString(); +} + // this function is not in use void FileScriptingInterface::downloadZip(QString path, const QString link) { QUrl url = QUrl(link); diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h index 4069e7cc78..c2b309ce43 100644 --- a/libraries/script-engine/src/FileScriptingInterface.h +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -34,6 +34,7 @@ private: bool isTempDir(QString tempDir); QStringList unzipFile(QString path, QString tempDir); void recursiveFileScan(QFileInfo file, QString* dirName); + QString downloadBlocksZip(QUrl url); void downloadZip(QString path, const QString link); }; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 8902a5deee..ca9e4aa2b6 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -80,10 +80,9 @@ // Add button links. - /* Blocks not yet implemented $('#exploreBlocksMarketplace').on('click', function () { window.location = "https://vr.google.com/objects"; - });*/ + }); $('#exploreClaraMarketplace').on('click', function () { window.location = "https://clara.io/library?gameCheck=true&public=true"; }); @@ -157,7 +156,7 @@ // One file request at a time. if (isPreparing) { - console.log("WARNIKNG: Clara.io FBX: Prepare only one download at a time"); + console.log("WARNING: Clara.io FBX: Prepare only one download at a time"); return; } @@ -347,7 +346,6 @@ if (location.href.indexOf("google.com/") !== -1) { pageType = BLOCKS; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } - //if (pageType != BLOCKS) injectCommonCode(pageType === DIRECTORY); switch (pageType) { case DIRECTORY: @@ -358,7 +356,7 @@ break; case BLOCKS: console.log("in Blocks"); - //injectBlocksCode(); + injectBlocksCode(); console.log("blocks injection"); break; case CLARA: From a730da5299cccb8606c5078eceed7f6f648a72bd Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Wed, 9 Aug 2017 04:23:39 -0400 Subject: [PATCH 51/95] Account for PloyLine stroke width when calculating the dimensions of the PolyLilne's bounding box. --- libraries/entities/src/PolyLineEntityItem.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 61d5dd22ee..90e0a18a3f 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -182,15 +182,27 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); return; } + + // Find the max width of the strokes so we can account for that in the size of the bounding box + float maxWidth = 0.0f; + for (int i = 0; i < _strokeWidths.size(); ++i) { + if (_strokeWidths.at(i) > maxWidth) { + maxWidth = _strokeWidths.at(i); + qCDebug(entities) << "TTTTT " << maxWidth; + } + } glm::vec3 result; - result.x = fabsf(high.x) + fabsf(low.x); - result.y = fabsf(high.y) + fabsf(low.y); - result.z = fabsf(high.z) + fabsf(low.z); + float halfLineWidth = (maxWidth > 0.0f) ? maxWidth * 0.5f : 0.0f; + result.x = fabsf(high.x) + fabsf(low.x) + halfLineWidth; + result.y = fabsf(high.y) + fabsf(low.y) + halfLineWidth; + result.z = fabsf(high.z) + fabsf(low.z) + halfLineWidth; SpatiallyNestable::setScale(result); + // Center the poly line in the bounding box glm::vec3 point = _points.at(0); glm::vec3 startPointInScaleSpace = point - low; + startPointInScaleSpace += glm::vec3(halfLineWidth * 0.5f); glm::vec3 newRegistrationPoint = startPointInScaleSpace / result; EntityItem::setRegistrationPoint(newRegistrationPoint); } else { From cc69853ff1327a3154bdaf552ba918813dee6d82 Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Wed, 9 Aug 2017 04:37:47 -0400 Subject: [PATCH 52/95] Make requested style changes to code. --- libraries/entities/src/PolyLineEntityItem.cpp | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 90e0a18a3f..e5050a303a 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -96,7 +96,7 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { _points << point; _pointsChanged = true; - calculateScaleAndRegistrationPoint(); + calculateScaleAndRegistrationPoint(); return true; } @@ -142,7 +142,7 @@ bool PolyLineEntityItem::setLinePoints(const QVector& points) { _points = points; - calculateScaleAndRegistrationPoint(); + calculateScaleAndRegistrationPoint(); result = true; }); @@ -151,37 +151,37 @@ bool PolyLineEntityItem::setLinePoints(const QVector& points) { } void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { - glm::vec3 high(0.0f, 0.0f, 0.0f); - glm::vec3 low(0.0f, 0.0f, 0.0f); - for (int i = 0; i < _points.size(); i++) { - glm::vec3 point = _points.at(i); + glm::vec3 high(0.0f, 0.0f, 0.0f); + glm::vec3 low(0.0f, 0.0f, 0.0f); + for (int i = 0; i < _points.size(); i++) { + glm::vec3 point = _points.at(i); - if (point.x > high.x){ - high.x = point.x; - } else if (point.x < low.x) { - low.x = point.x; - } + if (point.x > high.x) { + high.x = point.x; + } else if (point.x < low.x) { + low.x = point.x; + } - if (point.y > high.y){ - high.y = point.y; - } else if (point.y < low.y) { - low.y = point.y; - } + if (point.y > high.y) { + high.y = point.y; + } else if (point.y < low.y) { + low.y = point.y; + } - if (point.z > high.z){ - high.z = point.z; - } else if (point.z < low.z) { - low.z = point.z; - } - } - const float EPSILON = 0.0001f; - if (_points.size() > 1) { - // if all the points in the Polyline are at the same place in space, use default dimension settings - if ((low - high).length() < EPSILON) { - SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); - EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); - return; - } + if (point.z > high.z) { + high.z = point.z; + } else if (point.z < low.z) { + low.z = point.z; + } + } + const float EPSILON = 0.0001f; + if (_points.size() > 1) { + // if all the points in the Polyline are at the same place in space, use default dimension settings + if ((low - high).length() < EPSILON) { + SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); + EntityItem::setRegistrationPoint(glm::vec3(0.5f)); + return; + } // Find the max width of the strokes so we can account for that in the size of the bounding box float maxWidth = 0.0f; @@ -192,24 +192,24 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { } } - glm::vec3 result; + glm::vec3 result; float halfLineWidth = (maxWidth > 0.0f) ? maxWidth * 0.5f : 0.0f; result.x = fabsf(high.x) + fabsf(low.x) + halfLineWidth; result.y = fabsf(high.y) + fabsf(low.y) + halfLineWidth; result.z = fabsf(high.z) + fabsf(low.z) + halfLineWidth; - SpatiallyNestable::setScale(result); + SpatiallyNestable::setScale(result); // Center the poly line in the bounding box - glm::vec3 point = _points.at(0); - glm::vec3 startPointInScaleSpace = point - low; + glm::vec3 point = _points.at(0); + glm::vec3 startPointInScaleSpace = point - low; startPointInScaleSpace += glm::vec3(halfLineWidth * 0.5f); - glm::vec3 newRegistrationPoint = startPointInScaleSpace / result; - EntityItem::setRegistrationPoint(newRegistrationPoint); - } else { - // if Polyline has only one or fewer points, use default dimension settings - SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); - EntityItem::setRegistrationPoint(glm::vec3(0.0f, 0.0f, 0.0f)); - } + glm::vec3 newRegistrationPoint = startPointInScaleSpace / result; + EntityItem::setRegistrationPoint(newRegistrationPoint); + } else { + // if Polyline has only one or fewer points, use default dimension settings + SpatiallyNestable::setScale(glm::vec3(1.0f, 1.0f, 1.0f)); + EntityItem::setRegistrationPoint(glm::vec3(0.5f)); + } } int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, From 87139f5d822e197097905502079d4c8734395a52 Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Wed, 9 Aug 2017 04:46:42 -0400 Subject: [PATCH 53/95] Remove debug print --- libraries/entities/src/PolyLineEntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index e5050a303a..4d27330b3e 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -188,7 +188,6 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { for (int i = 0; i < _strokeWidths.size(); ++i) { if (_strokeWidths.at(i) > maxWidth) { maxWidth = _strokeWidths.at(i); - qCDebug(entities) << "TTTTT " << maxWidth; } } From 17acf0520d5e682f6d4d666deb5f050cf26511f2 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 9 Aug 2017 11:08:14 -0700 Subject: [PATCH 54/95] Download from blocks in marketplace working --- interface/src/Application.cpp | 25 ++++++++++++++++--- .../src/FileScriptingInterface.cpp | 4 +-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c887007fae..60b7477ac5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2779,7 +2779,8 @@ bool Application::importFromZIP(const QString& filePath) { QUrl empty; // handle Blocks download from Marketplace if (filePath.contains("vr.google.com/downloads")) { - qApp->getFileDownloadInterface()->runUnzip("", filePath, true, true); + addAssetToWorldFromURL(filePath); + //qApp->getFileDownloadInterface()->runUnzip("", filePath, true, true); } else { qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true); } @@ -6220,8 +6221,16 @@ void Application::showAssetServerWidget(QString filePath) { void Application::addAssetToWorldFromURL(QString url) { qInfo(interfaceapp) << "Download model and add to world from" << url; - - QString filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. + + QString filename; + if (url.contains("filename")) { + filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. + } + if (url.contains("vr.google.com/downloads")) { + QRegExp blocksName("\/.*\.zip"); + //filename = url.section(blocksName); + filename = "blocks"; + } if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { QString errorInfo = "You do not have permissions to write to the Asset Server."; @@ -6242,7 +6251,15 @@ void Application::addAssetToWorldFromURLRequestFinished() { auto url = request->getUrl().toString(); auto result = request->getResult(); - QString filename = url.section("filename=", 1, 1); // Filename from trailing "?filename=" URL parameter. + QString filename; + if (url.contains("filename")) { + filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. + } + if (url.contains("vr.google.com/downloads")) { + QRegExp blocksName("\/.*\.zip"); + //filename = url.section(blocksName); + filename = "blocks"; + } if (result == ResourceRequest::Success) { qInfo(interfaceapp) << "Downloaded model from" << url; diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index ba1e9bcddf..1a121f3059 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -34,10 +34,10 @@ FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isZip) { qCDebug(scriptengine) << "Url that was downloaded: " + url.toString(); - if ((url.toString()).contains("vr.google.com/downloads")) { + /*if ((url.toString()).contains("vr.google.com/downloads")) { path = downloadBlocksZip(url); - } + }*/ qCDebug(scriptengine) << "Path where download is saved: " + path; QString fileName = "/" + path.section("/", -1); QString tempDir = path; From 6157f4fa55c4c1ce82657aced2c3bd75982bc283 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 9 Aug 2017 11:56:25 -0700 Subject: [PATCH 55/95] script fixes --- scripts/system/controllers/handControllerGrab.js | 1 + scripts/system/controllers/handControllerPointer.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index dccf8e890b..44f79a5570 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3442,6 +3442,7 @@ function MyController(hand) { }; this.offEnter = function() { + var existingSearchDistance = this.searchSphereDistance; this.release(); if (hoveredEntityID) { diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index f169204206..538fe0b1e4 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -160,7 +160,7 @@ var systemLaserOn = false; var triggerPath = { type: "line3d", - color: LASER_SEARCH_COLOR, + color: LASER_TRIGGER_COLOR, ignoreRayIntersection: true, visible: true, alpha: LASER_ALPHA, @@ -171,7 +171,7 @@ var triggerPath = { var triggerEnd = { type: "sphere", dimensions: {x: END_DIAMETER, y: END_DIAMETER, z: END_DIAMETER}, - color: LASER_SEARCH_COLOR, + color: LASER_TRIGGER_COLOR, ignoreRayIntersection: true, visible: true, alpha: LASER_ALPHA, @@ -181,7 +181,7 @@ var triggerEnd = { var searchPath = { type: "line3d", - color: LASER_TRIGGER_COLOR, + color: LASER_SEARCH_COLOR, ignoreRayIntersection: true, visible: true, alpha: LASER_ALPHA, @@ -192,7 +192,7 @@ var searchPath = { var searchEnd = { type: "sphere", dimensions: {x: END_DIAMETER, y: END_DIAMETER, z: END_DIAMETER}, - color: LASER_TRIGGER_COLOR, + color: LASER_SEARCH_COLOR, ignoreRayIntersection: true, visible: true, alpha: LASER_ALPHA, From 1ac9536f9572f93568ab7161df83a4c463d76348 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 9 Aug 2017 15:56:07 -0700 Subject: [PATCH 56/95] Downloading blocks from marketplace in own asset folder --- interface/src/Application.cpp | 29 +++++++++++-------- interface/src/Application.h | 4 +-- .../src/FileScriptingInterface.cpp | 28 +++++------------- .../src/FileScriptingInterface.h | 5 ++-- 4 files changed, 29 insertions(+), 37 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 60b7477ac5..efd6bd9f48 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2780,9 +2780,8 @@ bool Application::importFromZIP(const QString& filePath) { // handle Blocks download from Marketplace if (filePath.contains("vr.google.com/downloads")) { addAssetToWorldFromURL(filePath); - //qApp->getFileDownloadInterface()->runUnzip("", filePath, true, true); } else { - qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true); + qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true, false); } return true; } @@ -6227,9 +6226,8 @@ void Application::addAssetToWorldFromURL(QString url) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. } if (url.contains("vr.google.com/downloads")) { - QRegExp blocksName("\/.*\.zip"); - //filename = url.section(blocksName); - filename = "blocks"; + filename = url.section('/', -1); + filename.remove(".zip?noDownload=false"); } if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { @@ -6252,13 +6250,15 @@ void Application::addAssetToWorldFromURLRequestFinished() { auto result = request->getResult(); QString filename; + bool isBlocks = false; + if (url.contains("filename")) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. } if (url.contains("vr.google.com/downloads")) { - QRegExp blocksName("\/.*\.zip"); - //filename = url.section(blocksName); - filename = "blocks"; + filename = url.section('/', -1); + filename.remove(".zip?noDownload=false"); + isBlocks = true; } if (result == ResourceRequest::Success) { @@ -6274,7 +6274,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { if (tempFile.open(QIODevice::WriteOnly)) { tempFile.write(request->getData()); addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key. - qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false); + qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false, isBlocks); } else { QString errorInfo = "Couldn't open temporary file for download"; qWarning(interfaceapp) << errorInfo; @@ -6304,7 +6304,7 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { addAssetToWorldError(filename, "Couldn't unzip file " + filename + "."); } -void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip) { +void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocks) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString path = filePath; @@ -6313,6 +6313,11 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip) QString assetFolder = zipFile.section("/", -1); assetFolder.remove(".zip"); mapping = "/" + assetFolder + "/" + filename; + } else if (isBlocks) { + qCDebug(interfaceapp) << "Path to asset folder: " << zipFile; + QString assetFolder = zipFile.section('/', -1); + assetFolder.remove(".zip?noDownload=false"); + mapping = "/" + assetFolder + "/" + filename; } else { mapping = "/" + filename; } @@ -6692,12 +6697,12 @@ void Application::onAssetToWorldMessageBoxClosed() { } -void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip) { +void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocks) { if (autoAdd) { if (!unzipFile.isEmpty()) { for (int i = 0; i < unzipFile.length(); i++) { qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i); - addAssetToWorld(unzipFile.at(i), zipFile, isZip); + addAssetToWorld(unzipFile.at(i), zipFile, isZip, isBlocks); } } else { addAssetToWorldUnzipFailure(zipFile); diff --git a/interface/src/Application.h b/interface/src/Application.h index f8eb393f9e..516ea6ed3a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -331,14 +331,14 @@ public slots: // FIXME: Move addAssetToWorld* methods to own class? void addAssetToWorldFromURL(QString url); void addAssetToWorldFromURLRequestFinished(); - void addAssetToWorld(QString filePath, QString zipFile, bool isZip); + void addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocks); void addAssetToWorldUnzipFailure(QString filePath); void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy); void addAssetToWorldUpload(QString filePath, QString mapping); void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash); void addAssetToWorldAddEntity(QString filePath, QString mapping); - void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip); + void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip, bool isBlocks); FileScriptingInterface* getFileDownloadInterface() { return _fileDownload; } diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 1a121f3059..681156973b 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -32,14 +32,11 @@ FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent // nothing for now } -void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isZip) { +void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isZip, bool isBlocks) { qCDebug(scriptengine) << "Url that was downloaded: " + url.toString(); - /*if ((url.toString()).contains("vr.google.com/downloads")) { - - path = downloadBlocksZip(url); - }*/ qCDebug(scriptengine) << "Path where download is saved: " + path; QString fileName = "/" + path.section("/", -1); + qCDebug(scriptengine) << "Filename: " << fileName; QString tempDir = path; if (!isZip) { tempDir.remove(fileName); @@ -60,11 +57,14 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool if (!fileList.isEmpty()) { qCDebug(scriptengine) << "File to upload: " + fileList.first(); - } - else { + } else { qCDebug(scriptengine) << "Unzip failed"; } - emit unzipResult(path, fileList, autoAdd, isZip); + + if (path.contains("vr.google.com/downloads")) { + isZip = true; + } + emit unzipResult(path, fileList, autoAdd, isZip, isBlocks); } @@ -115,18 +115,6 @@ QString FileScriptingInterface::convertUrlToPath(QUrl url) { return newUrl; } -// handles a download from Blocks in the marketplace -QString FileScriptingInterface::downloadBlocksZip(QUrl url) { - qCDebug(scriptengine) << "Made it to the download blocks! " << url.toString(); - - /*auto request = DependencyManager::get()->createResourceRequest(nullptr, url); - connect(request, &ResourceRequest::finished, this, [this, url] { - unzipFile(url, ""); // so intellisense isn't mad - }); - request->send();*/ - return url.toString(); -} - // this function is not in use void FileScriptingInterface::downloadZip(QString path, const QString link) { QUrl url = QUrl(link); diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h index c2b309ce43..e4c27dbf7f 100644 --- a/libraries/script-engine/src/FileScriptingInterface.h +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -24,17 +24,16 @@ public: public slots: QString convertUrlToPath(QUrl url); - void runUnzip(QString path, QUrl url, bool autoAdd, bool isZip); + void runUnzip(QString path, QUrl url, bool autoAdd, bool isZip, bool isBlocks); QString getTempDir(); signals: - void unzipResult(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip); + void unzipResult(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocks); private: bool isTempDir(QString tempDir); QStringList unzipFile(QString path, QString tempDir); void recursiveFileScan(QFileInfo file, QString* dirName); - QString downloadBlocksZip(QUrl url); void downloadZip(QString path, const QString link); }; From 74c90d632380c85fb24c4cd12b75a05ecf9b01b9 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 9 Aug 2017 16:08:47 -0700 Subject: [PATCH 57/95] minor typo --- scripts/system/html/js/marketplacesInject.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 179cefd205..9526bd051a 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -400,7 +400,8 @@ break; case CLARA: injectClaraCode(); - break; case BLOCKS: + break; + case BLOCKS: console.log("in Blocks"); injectBlocksCode(); console.log("blocks injection"); From 69a13052abaf305245bf8437b636eb90699aa598 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 9 Aug 2017 17:23:08 -0700 Subject: [PATCH 58/95] commented out blocks injection --- scripts/system/html/js/marketplacesInject.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 9526bd051a..644a1aa046 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -403,8 +403,9 @@ break; case BLOCKS: console.log("in Blocks"); - injectBlocksCode(); - console.log("blocks injection"); + //injectBlocksCode(); + //console.log("blocks injection"); + break; case HIFI_ITEM_PAGE: injectHiFiItemPageCode(); break; From d3c76c99c20ab8598dfea5ced9487b9920f95c2b Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 9 Aug 2017 17:28:05 -0700 Subject: [PATCH 59/95] See all markets button working again --- .../resources/qml/hifi/commerce/Checkout.qml | 17 +++++- scripts/system/html/js/marketplacesInject.js | 31 +++++++---- scripts/system/marketplaces/marketplaces.js | 52 +++++++++---------- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml index 0b5d5978dd..48d5f5b1d5 100644 --- a/interface/resources/qml/hifi/commerce/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -25,6 +25,7 @@ Rectangle { id: checkoutRoot; property string itemId; + property string itemHref; // Style color: hifi.colors.baseGray; Hifi.QmlCommerce { @@ -234,6 +235,7 @@ Rectangle { // "Cancel" button HifiControlsUit.Button { + id: cancelButton; color: hifi.buttons.black; colorScheme: hifi.colorSchemes.dark; anchors.top: parent.top; @@ -251,6 +253,8 @@ Rectangle { // "Buy" button HifiControlsUit.Button { + property bool buyFailed: false; + id: buyButton; color: hifi.buttons.black; colorScheme: hifi.colorSchemes.dark; anchors.top: parent.top; @@ -262,7 +266,11 @@ Rectangle { width: parent.width/2 - anchors.rightMargin*2; text: "Buy" onClicked: { - sendToScript({method: 'checkout_buyClicked', params: {success: commerce.buy(itemId, parseInt(itemPriceText.text))}}); + if (buyFailed) { + sendToScript({method: 'checkout_cancelClicked', params: itemId}); + } else { + sendToScript({method: 'checkout_buyClicked', success: commerce.buy(itemId, parseInt(itemPriceText.text)), itemId: itemId, itemHref: itemHref}); + } } } } @@ -293,6 +301,13 @@ Rectangle { itemNameText.text = message.params.itemName; itemAuthorText.text = message.params.itemAuthor; itemPriceText.text = message.params.itemPrice; + itemHref = message.params.itemHref; + buyButton.text = "Buy"; + buyButton.buyFailed = false; + break; + case 'buyFailed': + buyButton.text = "Buy Failed"; + buyButton.buyFailed = true; break; default: console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message)); diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 644a1aa046..e078112360 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -93,24 +93,29 @@ }); } - function buyButtonClicked(id, name, author, price) { + function buyButtonClicked(id, name, author, price, href) { EventBridge.emitWebEvent(JSON.stringify({ type: "CHECKOUT", itemId: id, itemName: name, itemAuthor: author, - itemPrice: price + itemPrice: price, + itemHref: href })); } function injectBuyButtonOnMainPage() { - $('.grid-item').find('#price-or-edit').find('a').attr('href', '#'); + $('.grid-item').find('#price-or-edit').find('a').each(function() { + $(this).attr('data-href', $(this).attr('href')); + $(this).attr('href', '#'); + }); $('.grid-item').find('#price-or-edit').find('.price').text("BUY"); $('.grid-item').find('#price-or-edit').find('a').on('click', function () { buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'), $(this).closest('.grid-item').find('.item-title').text(), $(this).closest('.grid-item').find('.creator').find('.value').text(), - 10); + 10, + $(this).attr('data-href')); }); } @@ -137,13 +142,15 @@ function injectHiFiItemPageCode() { if (confirmAllPurchases) { + var href = $('#side-info').find('.btn').attr('href'); $('#side-info').find('.btn').attr('href', '#'); $('#side-info').find('.btn').html('Buy Item '); $('#side-info').find('.btn').on('click', function () { buyButtonClicked(window.location.pathname.split("/")[3], $('#top-center').find('h1').text(), $('#creator').find('.value').text(), - 10); + 10, + href); }); } } @@ -415,16 +422,18 @@ function onLoad() { EventBridge.scriptEventReceived.connect(function (message) { - var parsedJsonMessage = JSON.parse(message); - if (message.slice(0, CAN_WRITE_ASSETS.length) === CAN_WRITE_ASSETS) { canWriteAssets = message.slice(-4) === "true"; } else if (message.slice(0, CLARA_IO_CANCEL_DOWNLOAD.length) === CLARA_IO_CANCEL_DOWNLOAD) { cancelClaraDownload(); - } else if (parsedJsonMessage.type === "marketplaces") { - if (parsedJsonMessage.action === "inspectionModeSetting") { - confirmAllPurchases = !!parsedJsonMessage.data; - injectCode(); + } else { + var parsedJsonMessage = JSON.parse(message); + + if (parsedJsonMessage.type === "marketplaces") { + if (parsedJsonMessage.action === "inspectionModeSetting") { + confirmAllPurchases = !!parsedJsonMessage.data; + injectCode(); + } } } }); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index e29510b4c8..4dd7438ac2 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -101,31 +101,14 @@ Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); function onMessage(message) { - var parsedJsonMessage = JSON.parse(message); - if (parsedJsonMessage.type === "CHECKOUT") { - tablet.sendToQml({ method: 'updateCheckoutQML', params: parsedJsonMessage }); - tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); - } else if (parsedJsonMessage.type === "REQUEST_SETTING") { - tablet.emitScriptEvent(JSON.stringify({ - type: "marketplaces", - action: "inspectionModeSetting", - data: Settings.getValue("inspectionMode", false) - })); - } if (message === GOTO_DIRECTORY) { tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL); - } - - if (message === QUERY_CAN_WRITE_ASSETS) { + } else if (message === QUERY_CAN_WRITE_ASSETS) { tablet.emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets()); - } - - if (message === WARN_USER_NO_PERMISSIONS) { + } else if (message === WARN_USER_NO_PERMISSIONS) { Window.alert(NO_PERMISSIONS_ERROR_MESSAGE); - } - - if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) { + } else if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) { if (isDownloadBeingCancelled) { return; } @@ -137,18 +120,26 @@ Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON); } return; - } - - if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) { + } else if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) { if (messageBox !== null) { Window.closeMessageBox(messageBox); messageBox = null; } return; - } - - if (message === CLARA_IO_CANCELLED_DOWNLOAD) { + } else if (message === CLARA_IO_CANCELLED_DOWNLOAD) { isDownloadBeingCancelled = false; + } else { + var parsedJsonMessage = JSON.parse(message); + if (parsedJsonMessage.type === "CHECKOUT") { + tablet.sendToQml({ method: 'updateCheckoutQML', params: parsedJsonMessage }); + tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); + } else if (parsedJsonMessage.type === "REQUEST_SETTING") { + tablet.emitScriptEvent(JSON.stringify({ + type: "marketplaces", + action: "inspectionModeSetting", + data: Settings.getValue("inspectionMode", false) + })); + } } } @@ -207,7 +198,14 @@ //tablet.popFromStack(); break; case 'checkout_buyClicked': - print("fromQml: " + JSON.stringify(message)); + if (message.success === true) { + tablet.gotoWebScreen(message.itemHref); + Script.setTimeout(function () { + tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.itemId, MARKETPLACES_INJECT_SCRIPT_URL); + }, 100); + } else { + tablet.sendToQml({ method: 'buyFailed' }); + } //tablet.popFromStack(); break; default: From b0c91547b421fb634353c1b54131e5bab460c109 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 10 Aug 2017 14:14:09 -0700 Subject: [PATCH 60/95] Fixed WebGL rendering --- interface/src/main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index a19055d4da..084e540ff4 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -216,7 +216,17 @@ int main(int argc, const char* argv[]) { SandboxUtils::runLocalSandbox(serverContentPath, true, noUpdater); } - Application app(argc, const_cast(argv), startupTime, runningMarkerExisted); + // to enable WebGL rendering + char* additionalCommandLineArg = (char*)"--ignore-gpu-blacklist"; + int newArgc = argc + 1; + char** newArgv = new char*[newArgc]; + for (int i = 0; i < argc; ++i) { + newArgv[i] = (char*)argv[i]; + } + newArgv[argc] = additionalCommandLineArg; + + Application app(newArgc, const_cast(newArgv), startupTime, runningMarkerExisted); + delete[] newArgv; // If we failed the OpenGLVersion check, log it. if (override) { From 28476960bb3d6560e941e260c99e2a9b91ca9f73 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 10 Aug 2017 14:23:45 -0700 Subject: [PATCH 61/95] Moved Blocks to tablet app --- scripts/defaultScripts.js | 1 + scripts/system/html/js/marketplacesInject.js | 28 +++----------------- scripts/system/html/marketplaces.html | 12 --------- scripts/system/marketplaces/blocksApp.js | 22 +++++++++++++++ 4 files changed, 26 insertions(+), 37 deletions(-) create mode 100644 scripts/system/marketplaces/blocksApp.js diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 2270118861..bddb2ae703 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -24,6 +24,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/makeUserConnection.js", "system/tablet-goto.js", "system/marketplaces/marketplaces.js", + "system/marketplaces/blocksApp.js", // temporarily in default scripts for testing purposes "system/edit.js", "system/notifications.js", "system/dialTone.js", diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index e078112360..dd239463d2 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -59,7 +59,7 @@ $("body").append( '
    ' + (!isInitialHiFiPage ? '' : '') + - (isInitialHiFiPage ? '🛈 Get items from Blocks and Clara.io!' : '') + + (isInitialHiFiPage ? '🛈 Get items from Clara.io!' : '') + (!isDirectoryPage ? '' : '') + (isDirectoryPage ? '🛈 Select a marketplace to explore.' : '') + '
    ' @@ -82,9 +82,6 @@ // Add button links. - $('#exploreBlocksMarketplace').on('click', function () { - window.location = "https://vr.google.com/objects"; - }); $('#exploreClaraMarketplace').on('click', function () { window.location = "https://clara.io/library?gameCheck=true&public=true"; }); @@ -155,18 +152,6 @@ } } - function injectBlocksCode() { - // Make space for marketplaces footer in Blocks pages. - /*$("body").append( - '
    ' + - '' + - '
    ' - );*/ - $("body").append( - '

    hello

    ' - ); - } - function updateClaraCode() { // Have to repeatedly update Clara page because its content can change dynamically without location.href changing. @@ -387,13 +372,11 @@ function injectCode() { var DIRECTORY = 0; var HIFI = 1; - var BLOCKS = 2; - var CLARA = 3; - var HIFI_ITEM_PAGE = 4; + var CLARA = 2; + var HIFI_ITEM_PAGE = 3; var pageType = DIRECTORY; if (location.href.indexOf("highfidelity.com/") !== -1) { pageType = HIFI; } - if (location.href.indexOf("google.com/") !== -1) { pageType = BLOCKS; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } if (location.href.indexOf("highfidelity.com/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } @@ -408,11 +391,6 @@ case CLARA: injectClaraCode(); break; - case BLOCKS: - console.log("in Blocks"); - //injectBlocksCode(); - //console.log("blocks injection"); - break; case HIFI_ITEM_PAGE: injectHiFiItemPageCode(); break; diff --git a/scripts/system/html/marketplaces.html b/scripts/system/html/marketplaces.html index 10184ae101..9e001c064f 100644 --- a/scripts/system/html/marketplaces.html +++ b/scripts/system/html/marketplaces.html @@ -31,18 +31,6 @@
    -
    -
    - -
    -
    -

    Blocks, released by Google, allows anyone to create 3D models using just a few simple tools. Browse through other users' creations for low-poly assets to add to your world.

    -
    -
    - -
    -
    -
    diff --git a/scripts/system/marketplaces/blocksApp.js b/scripts/system/marketplaces/blocksApp.js new file mode 100644 index 0000000000..46a102042e --- /dev/null +++ b/scripts/system/marketplaces/blocksApp.js @@ -0,0 +1,22 @@ +(function() { + var APP_NAME = "BLOCKS"; + var APP_URL = "https://vr.google.com/objects/"; + var APP_ICON = "https://hifi-content.s3.amazonaws.com/faye/gemstoneMagicMaker/gemstoneAppIcon.svg"; + + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var button = tablet.addButton({ + icon: APP_ICON, + text: APP_NAME + }); + + function onClicked() { + tablet.gotoWebScreen(APP_URL); + } + button.clicked.connect(onClicked); + + function cleanup() { + tablet.removeButton(button); + } + + Script.scriptEnding.connect(cleanup); +}()); \ No newline at end of file From d0d5ac8dd12385abb5cd1e9f95d0db97e65590e4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 10 Aug 2017 15:32:58 -0700 Subject: [PATCH 62/95] switch to stl wherever possible, use bitset instead of unsigned ints --- interface/src/raypick/JointRayPick.cpp | 4 +- interface/src/raypick/JointRayPick.h | 6 +- interface/src/raypick/LaserPointer.cpp | 44 +++---- interface/src/raypick/LaserPointer.h | 21 +-- interface/src/raypick/LaserPointerManager.cpp | 84 ++++++------ interface/src/raypick/LaserPointerManager.h | 24 ++-- .../LaserPointerScriptingInterface.cpp | 12 +- .../raypick/LaserPointerScriptingInterface.h | 2 +- interface/src/raypick/MouseRayPick.cpp | 2 +- interface/src/raypick/MouseRayPick.h | 2 +- interface/src/raypick/RayPick.cpp | 2 +- interface/src/raypick/RayPick.h | 76 ++++++++++- interface/src/raypick/RayPickManager.cpp | 120 +++++++++--------- interface/src/raypick/RayPickManager.h | 66 ++++------ interface/src/raypick/StaticRayPick.cpp | 2 +- interface/src/raypick/StaticRayPick.h | 2 +- 16 files changed, 268 insertions(+), 201 deletions(-) diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index 6803700e4b..48ab908201 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -13,7 +13,7 @@ #include "DependencyManager.h" #include "avatar/AvatarManager.h" -JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance, const bool enabled) : +JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), _posOffset(posOffset), @@ -23,7 +23,7 @@ JointRayPick::JointRayPick(const QString& jointName, const glm::vec3& posOffset, const PickRay JointRayPick::getPickRay(bool& valid) const { auto myAvatar = DependencyManager::get()->getMyAvatar(); - int jointIndex = myAvatar->getJointIndex(_jointName); + int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName)); bool useAvatarHead = _jointName == "Avatar"; const int INVALID_JOINT = -1; if (jointIndex != INVALID_JOINT || useAvatarHead) { diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index 0631372bdb..3cd622fbbe 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -13,17 +13,15 @@ #include "RayPick.h" -#include - class JointRayPick : public RayPick { public: - JointRayPick(const QString& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); const PickRay getPickRay(bool& valid) const override; private: - QString _jointName; + std::string _jointName; glm::vec3 _posOffset; glm::vec3 _dirOffset; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 9dc1bdd72e..0e1d384e5d 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -13,7 +13,7 @@ #include "Application.h" #include "avatar/AvatarManager.h" -LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, +LaserPointer::LaserPointer(const QVariantMap& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), @@ -24,14 +24,14 @@ LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash()->createRayPick(rayProps); - for (QString& state : _renderStates.keys()) { - if (!enabled || state != _currentRenderState) { - disableRenderState(_renderStates[state]); + for (auto& state : _renderStates) { + if (!enabled || state.first != _currentRenderState) { + disableRenderState(state.second); } } - for (QString& state : _defaultRenderStates.keys()) { - if (!enabled || state != _currentRenderState) { - disableRenderState(_defaultRenderStates[state].second); + for (auto& state : _defaultRenderStates) { + if (!enabled || state.first != _currentRenderState) { + disableRenderState(state.second.second); } } } @@ -39,12 +39,12 @@ LaserPointer::LaserPointer(const QVariantMap& rayProps, const QHash()->removeRayPick(_rayPickUID); - for (RenderState& renderState : _renderStates) { - renderState.deleteOverlays(); - } - for (QPair& renderState : _defaultRenderStates) { + for (auto& renderState : _renderStates) { renderState.second.deleteOverlays(); } + for (auto& renderState : _defaultRenderStates) { + renderState.second.second.deleteOverlays(); + } } void LaserPointer::enable() { @@ -55,29 +55,29 @@ void LaserPointer::enable() { void LaserPointer::disable() { DependencyManager::get()->disableRayPick(_rayPickUID); _renderingEnabled = false; - if (!_currentRenderState.isEmpty()) { - if (_renderStates.contains(_currentRenderState)) { + if (!_currentRenderState.empty()) { + if (_renderStates.find(_currentRenderState) != _renderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); } - if (_defaultRenderStates.contains(_currentRenderState)) { + if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_defaultRenderStates[_currentRenderState].second); } } } -void LaserPointer::setRenderState(const QString& state) { - if (!_currentRenderState.isEmpty() && state != _currentRenderState) { - if (_renderStates.contains(_currentRenderState)) { +void LaserPointer::setRenderState(const std::string& state) { + if (!_currentRenderState.empty() && state != _currentRenderState) { + if (_renderStates.find(_currentRenderState) != _renderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); } - if (_defaultRenderStates.contains(_currentRenderState)) { + if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_defaultRenderStates[_currentRenderState].second); } } _currentRenderState = state; } -void LaserPointer::editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { +void LaserPointer::editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { updateRenderStateOverlay(_renderStates[state].getStartID(), startProps); updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps); updateRenderStateOverlay(_renderStates[state].getEndID(), endProps); @@ -181,13 +181,13 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { void LaserPointer::update() { RayPickResult prevRayPickResult = DependencyManager::get()->getPrevRayPickResult(_rayPickUID); - if (_renderingEnabled && !_currentRenderState.isEmpty() && _renderStates.contains(_currentRenderState) && prevRayPickResult.type != IntersectionType::NONE) { + if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && prevRayPickResult.type != IntersectionType::NONE) { updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, prevRayPickResult.distance, prevRayPickResult.objectID, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); - } else if (_renderingEnabled && !_currentRenderState.isEmpty() && _defaultRenderStates.contains(_currentRenderState)) { + } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), true); - } else if (!_currentRenderState.isEmpty()) { + } else if (!_currentRenderState.empty()) { disableRenderState(_renderStates[_currentRenderState]); disableRenderState(_defaultRenderStates[_currentRenderState].second); } diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 946b01d3ba..aaa9dad83f 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -48,7 +48,11 @@ private: class LaserPointer { public: - LaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, + + typedef std::unordered_map RenderStateMap; + typedef std::unordered_map> DefaultRenderStateMap; + + LaserPointer(const QVariantMap& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); ~LaserPointer(); @@ -57,9 +61,9 @@ public: void disable(); const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } - void setRenderState(const QString& state); + void setRenderState(const std::string& state); // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. - void editRenderState(const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); + void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(_rayPickUID, ignoreEntities); } void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(_rayPickUID, includeEntities); } @@ -68,25 +72,26 @@ public: void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(_rayPickUID, ignoreAvatars); } void setIncludeAvatars(const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(_rayPickUID, includeAvatars); } - void setLockEndUUID(QUuid objectID, const bool isOverlay) { _objectLockEnd = QPair(objectID, isOverlay); } + void setLockEndUUID(QUuid objectID, const bool isOverlay) { _objectLockEnd = std::pair(objectID, isOverlay); } void update(); private: bool _renderingEnabled; - QString _currentRenderState { "" }; - QHash _renderStates; - QHash> _defaultRenderStates; + std::string _currentRenderState { "" }; + RenderStateMap _renderStates; + DefaultRenderStateMap _defaultRenderStates; bool _faceAvatar; bool _centerEndY; bool _lockEnd; - QPair _objectLockEnd { QPair(QUuid(), false)}; + std::pair _objectLockEnd { std::pair(QUuid(), false)}; QUuid _rayPickUID; void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState); void disableRenderState(const RenderState& renderState); + }; #endif // hifi_LaserPointer_h diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 33f292b255..da20068cba 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -11,85 +11,87 @@ #include "LaserPointerManager.h" #include "RayPick.h" -QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, +QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); if (!laserPointer->getRayUID().isNull()) { - QWriteLocker lock(&_addLock); + WriteLock lock(_addLock); QUuid id = QUuid::createUuid(); - _laserPointersToAdd.enqueue(QPair>(id, laserPointer)); + _laserPointersToAdd.push(std::pair>(id, laserPointer)); return id; } return QUuid(); } void LaserPointerManager::removeLaserPointer(const QUuid uid) { - QWriteLocker lock(&_removeLock); - _laserPointersToRemove.enqueue(uid); + WriteLock lock(_removeLock); + _laserPointersToRemove.push(uid); } void LaserPointerManager::enableLaserPointer(const QUuid uid) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->enable(); } } void LaserPointerManager::disableLaserPointer(const QUuid uid) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->disable(); } } -void LaserPointerManager::setRenderState(QUuid uid, const QString & renderState) { - QReadLocker lock(&_containsLock); +void LaserPointerManager::setRenderState(QUuid uid, const std::string& renderState) { + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setRenderState(renderState); } } -void LaserPointerManager::editRenderState(QUuid uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { - QReadLocker lock(&_containsLock); +void LaserPointerManager::editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->editRenderState(state, startProps, pathProps, endProps); } } const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QReadLocker laserLock(_laserPointerLocks[uid].get()); + ReadLock laserLock(*_laserPointerLocks[uid]); return _laserPointers[uid]->getPrevRayPickResult(); } return RayPickResult(); } void LaserPointerManager::update() { - for (QUuid uid : _laserPointers.keys()) { + for (QUuid& uid : _laserPointers.keys()) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts - QReadLocker laserLock(_laserPointerLocks[uid].get()); + ReadLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->update(); } - QWriteLocker containsLock(&_containsLock); + WriteLock containsLock(_containsLock); { - QWriteLocker lock(&_addLock); - while (!_laserPointersToAdd.isEmpty()) { - QPair> laserPointerToAdd = _laserPointersToAdd.dequeue(); + WriteLock lock(_addLock); + while (!_laserPointersToAdd.empty()) { + std::pair> laserPointerToAdd = _laserPointersToAdd.front(); + _laserPointersToAdd.pop(); _laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second; - _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); + _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); } } { - QWriteLocker lock(&_removeLock); - while (!_laserPointersToRemove.isEmpty()) { - QUuid uid = _laserPointersToRemove.dequeue(); + WriteLock lock(_removeLock); + while (!_laserPointersToRemove.empty()) { + QUuid uid = _laserPointersToRemove.front(); + _laserPointersToRemove.pop(); _laserPointers.remove(uid); _laserPointerLocks.remove(uid); } @@ -97,57 +99,57 @@ void LaserPointerManager::update() { } void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setIgnoreEntities(ignoreEntities); } } void LaserPointerManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setIncludeEntities(includeEntities); } } void LaserPointerManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setIgnoreOverlays(ignoreOverlays); } } void LaserPointerManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setIncludeOverlays(includeOverlays); } } void LaserPointerManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setIgnoreAvatars(ignoreAvatars); } } void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setIncludeAvatars(includeAvatars); } } void LaserPointerManager::setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { - QReadLocker lock(&_containsLock); + ReadLock lock(_containsLock); if (_laserPointers.contains(uid)) { - QWriteLocker laserLock(_laserPointerLocks[uid].get()); + WriteLock laserLock(*_laserPointerLocks[uid]); _laserPointers[uid]->setLockEndUUID(objectID, isOverlay); } } diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 002b8ce38e..5e33ac77d8 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -11,9 +11,8 @@ #ifndef hifi_LaserPointerManager_h #define hifi_LaserPointerManager_h -#include -#include #include +#include #include #include "LaserPointer.h" @@ -23,13 +22,13 @@ class RayPickResult; class LaserPointerManager { public: - QUuid createLaserPointer(const QVariantMap& rayProps, const QHash& renderStates, QHash>& defaultRenderStates, + QUuid createLaserPointer(const QVariantMap& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); void removeLaserPointer(const QUuid uid); void enableLaserPointer(const QUuid uid); void disableLaserPointer(const QUuid uid); - void setRenderState(QUuid uid, const QString& renderState); - void editRenderState(QUuid uid, const QString& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); + void setRenderState(QUuid uid, const std::string& renderState); + void editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); const RayPickResult getPrevRayPickResult(const QUuid uid); void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); @@ -45,12 +44,15 @@ public: private: QHash> _laserPointers; - QHash> _laserPointerLocks; - QReadWriteLock _addLock; - QQueue>> _laserPointersToAdd; - QReadWriteLock _removeLock; - QQueue _laserPointersToRemove; - QReadWriteLock _containsLock; + QHash> _laserPointerLocks; + std::shared_mutex _addLock; + std::queue>> _laserPointersToAdd; + std::shared_mutex _removeLock; + std::queue _laserPointersToRemove; + std::shared_mutex _containsLock; + + typedef std::lock_guard WriteLock; + typedef std::shared_lock ReadLock; }; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 78a62d0ed8..9b7f18d436 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -40,30 +40,30 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert enabled = propertyMap["enabled"].toBool(); } - QHash renderStates; + LaserPointer::RenderStateMap renderStates; if (propertyMap["renderStates"].isValid()) { QList renderStateVariants = propertyMap["renderStates"].toList(); for (QVariant& renderStateVariant : renderStateVariants) { if (renderStateVariant.isValid()) { QVariantMap renderStateMap = renderStateVariant.toMap(); if (renderStateMap["name"].isValid()) { - QString name = renderStateMap["name"].toString(); + std::string name = renderStateMap["name"].toString().toStdString(); renderStates[name] = buildRenderState(renderStateMap); } } } } - QHash> defaultRenderStates; + LaserPointer::DefaultRenderStateMap defaultRenderStates; if (propertyMap["defaultRenderStates"].isValid()) { QList renderStateVariants = propertyMap["defaultRenderStates"].toList(); for (QVariant& renderStateVariant : renderStateVariants) { if (renderStateVariant.isValid()) { QVariantMap renderStateMap = renderStateVariant.toMap(); if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) { - QString name = renderStateMap["name"].toString(); + std::string name = renderStateMap["name"].toString().toStdString(); float distance = renderStateMap["distance"].toFloat(); - defaultRenderStates[name] = QPair(distance, buildRenderState(renderStateMap)); + defaultRenderStates[name] = std::pair(distance, buildRenderState(renderStateMap)); } } } @@ -90,7 +90,7 @@ void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& r endProps = propMap["end"]; } - qApp->getLaserPointerManager().editRenderState(uid, renderState, startProps, pathProps, endProps); + qApp->getLaserPointerManager().editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); } const RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 70d2e9a1fd..7866a5da51 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -28,7 +28,7 @@ public slots: Q_INVOKABLE void disableLaserPointer(QUuid uid) { qApp->getLaserPointerManager().disableLaserPointer(uid); } Q_INVOKABLE void removeLaserPointer(QUuid uid) { qApp->getLaserPointerManager().removeLaserPointer(uid); } Q_INVOKABLE void editRenderState(QUuid uid, const QString& renderState, const QVariant& properties); - Q_INVOKABLE void setRenderState(QUuid uid, const QString& renderState) { qApp->getLaserPointerManager().setRenderState(uid, renderState); } + Q_INVOKABLE void setRenderState(QUuid uid, const QString& renderState) { qApp->getLaserPointerManager().setRenderState(uid, renderState.toStdString()); } Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); } Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); } diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp index 39dcb74090..de59fde88d 100644 --- a/interface/src/raypick/MouseRayPick.cpp +++ b/interface/src/raypick/MouseRayPick.cpp @@ -14,7 +14,7 @@ #include "Application.h" #include "display-plugins/CompositorHelper.h" -MouseRayPick::MouseRayPick(const uint16_t filter, const float maxDistance, const bool enabled) : +MouseRayPick::MouseRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled) { } diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index 84d1c86e24..848a5de336 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -16,7 +16,7 @@ class MouseRayPick : public RayPick { public: - MouseRayPick(const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + MouseRayPick(const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); const PickRay getPickRay(bool& valid) const override; }; diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp index e807ef23ff..70170a8f85 100644 --- a/interface/src/raypick/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -10,7 +10,7 @@ // #include "RayPick.h" -RayPick::RayPick(const uint16_t filter, const float maxDistance, const bool enabled) : +RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) : _filter(filter), _maxDistance(maxDistance), _enabled(enabled) diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 48841b9518..e108145d55 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -17,17 +17,87 @@ #include "EntityItemID.h" #include "ui/overlays/Overlay.h" +class RayPickFilter { +public: + enum FlagBit { + PICK_NOTHING = 0, + PICK_ENTITIES, + PICK_OVERLAYS, + PICK_AVATARS, + PICK_HUD, + + PICK_COURSE, // if not set, does precise intersection, otherwise, doesn't + + PICK_INCLUDE_INVISIBLE, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements + PICK_INCLUDE_NONCOLLIDABLE, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements + + // NOT YET IMPLEMENTED + PICK_ALL_INTERSECTIONS, // if not set, returns closest intersection, otherwise, returns list of all intersections + + NUM_FLAGS, // Not a valid flag + }; + typedef std::bitset Flags; + + // The key is the Flags + Flags _flags; + + RayPickFilter() : _flags(PICK_NOTHING) {} + RayPickFilter(const Flags& flags) : _flags(flags) {} + + bool operator== (const RayPickFilter& rhs) const { return _flags == rhs._flags; } + bool operator!= (const RayPickFilter& rhs) const { return _flags != rhs._flags; } + + bool doesPickNothing() const { return _flags[PICK_NOTHING]; } + bool doesPickEntities() const { return _flags[PICK_ENTITIES]; } + bool doesPickOverlays() const { return _flags[PICK_OVERLAYS]; } + bool doesPickAvatars() const { return _flags[PICK_AVATARS]; } + bool doesPickHUD() const { return _flags[PICK_HUD]; } + + bool doesPickCourse() const { return _flags[PICK_COURSE]; } + bool doesPickInvisible() const { return _flags[PICK_INCLUDE_INVISIBLE]; } + bool doesPickNonCollidable() const { return _flags[PICK_INCLUDE_NONCOLLIDABLE]; } + + bool doesWantAllIntersections() const { return _flags[PICK_ALL_INTERSECTIONS]; } + + // Helpers for RayPickManager + Flags getEntityFlags() const { + Flags toReturn(PICK_ENTITIES); + if (doesPickInvisible()) { + toReturn |= Flags(PICK_INCLUDE_INVISIBLE); + } + if (doesPickNonCollidable()) { + toReturn |= Flags(PICK_INCLUDE_NONCOLLIDABLE); + } + return toReturn; + } + Flags getOverlayFlags() const { + Flags toReturn(PICK_OVERLAYS); + if (doesPickInvisible()) { + toReturn |= Flags(PICK_INCLUDE_INVISIBLE); + } + if (doesPickNonCollidable()) { + toReturn |= Flags(PICK_INCLUDE_NONCOLLIDABLE); + } + return toReturn; + } + Flags getAvatarFlags() const { return Flags(PICK_AVATARS); } + Flags getHUDFlags() const { return Flags(PICK_HUD); } + + static unsigned int getBitMask(FlagBit bit) { return 1 << bit; } + +}; + class RayPick { public: - RayPick(const uint16_t filter, const float maxDistance, const bool enabled); + RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled); virtual const PickRay getPickRay(bool& valid) const = 0; void enable() { _enabled = true; } void disable() { _enabled = false; } - const uint16_t& getFilter() { return _filter; } + const RayPickFilter& getFilter() { return _filter; } const float& getMaxDistance() { return _maxDistance; } const bool& isEnabled() { return _enabled; } const RayPickResult& getPrevRayPickResult() { return _prevResult; } @@ -48,7 +118,7 @@ public: void setIncludeAvatars(const QScriptValue& includeAvatars) { _includeAvatars = qVectorEntityItemIDFromScriptValue(includeAvatars); } private: - uint16_t _filter; + RayPickFilter _filter; float _maxDistance; bool _enabled; RayPickResult _prevResult; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index f7f22a66bb..0fe7fdb823 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -10,8 +10,6 @@ // #include "RayPickManager.h" -#include "RayPick.h" - #include "Application.h" #include "EntityScriptingInterface.h" #include "ui/overlays/Overlays.h" @@ -23,8 +21,8 @@ #include "StaticRayPick.h" #include "MouseRayPick.h" -bool RayPickManager::checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, unsigned int mask) { - if (cache.contains(ray) && cache[ray].contains(mask)) { +bool RayPickManager::checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayPickFilter::Flags& mask) { + if (cache.contains(ray) && cache[ray].find(mask) != cache[ray].end()) { if (cache[ray][mask].distance < res.distance) { res = cache[ray][mask]; } @@ -33,7 +31,7 @@ bool RayPickManager::checkAndCompareCachedResults(QPair& r return false; } -void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, QPair& ray, RayPickCache& cache) { +void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayPickFilter::Flags& mask, RayPickResult& res, QPair& ray, RayPickCache& cache) { if (intersects) { cache[ray][mask] = resTemp; if (resTemp.distance < res.distance) { @@ -48,7 +46,7 @@ void RayPickManager::update() { RayPickCache results; for (auto& uid : _rayPicks.keys()) { std::shared_ptr rayPick = _rayPicks[uid]; - if (!rayPick->isEnabled() || rayPick->getFilter() == RayPickMask::PICK_NOTHING || rayPick->getMaxDistance() < 0.0f) { + if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) { continue; } @@ -62,12 +60,12 @@ void RayPickManager::update() { QPair rayKey = QPair(ray.origin, ray.direction); RayPickResult res; - if (rayPick->getFilter() & RayPickMask::PICK_ENTITIES) { + if (rayPick->getFilter().doesPickEntities()) { RayToEntityIntersectionResult entityRes; bool fromCache = true; - unsigned int invisible = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE; - unsigned int noncollidable = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; - unsigned int entityMask = RayPickMask::PICK_ENTITIES | invisible | noncollidable; + bool invisible = rayPick->getFilter().doesPickInvisible(); + bool noncollidable = rayPick->getFilter().doesPickNonCollidable(); + RayPickFilter::Flags entityMask = rayPick->getFilter().getEntityFlags(); if (!checkAndCompareCachedResults(rayKey, results, res, entityMask)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, rayPick->getIncludeEntites(), rayPick->getIgnoreEntites(), !invisible, !noncollidable); fromCache = false; @@ -79,12 +77,12 @@ void RayPickManager::update() { } } - if (rayPick->getFilter() & RayPickMask::PICK_OVERLAYS) { + if (rayPick->getFilter().doesPickOverlays()) { RayToOverlayIntersectionResult overlayRes; bool fromCache = true; - unsigned int invisible = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE; - unsigned int noncollidable = rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; - unsigned int overlayMask = RayPickMask::PICK_OVERLAYS | invisible | noncollidable; + bool invisible = rayPick->getFilter().doesPickInvisible(); + bool noncollidable = rayPick->getFilter().doesPickNonCollidable(); + RayPickFilter::Flags overlayMask = rayPick->getFilter().getOverlayFlags(); if (!checkAndCompareCachedResults(rayKey, results, res, overlayMask)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, rayPick->getIncludeOverlays(), rayPick->getIgnoreOverlays(), !invisible, !noncollidable); fromCache = false; @@ -96,22 +94,24 @@ void RayPickManager::update() { } } - if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_AVATARS)) { + if (rayPick->getFilter().doesPickAvatars()) { + RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags(); + if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) { RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars()); - cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), RayPickMask::PICK_AVATARS, res, rayKey, results); + cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), avatarMask, res, rayKey, results); } } // Can't intersect with HUD in desktop mode - if (rayPick->getFilter() & RayPickMask::PICK_HUD && DependencyManager::get()->isHMDMode()) { - if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_HUD)) { + if (rayPick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { + RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags(); + if (!checkAndCompareCachedResults(rayKey, results, res, hudMask)) { glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(ray.origin, ray.direction); - cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes), RayPickMask::PICK_HUD, res, rayKey, results); + cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes), hudMask, res, rayKey, results); } } - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { rayPick->setRayPickResult(res); } else { @@ -119,20 +119,22 @@ void RayPickManager::update() { } } - QWriteLocker containsLock(&_containsLock); + WriteLock containsLock(_containsLock); { - QWriteLocker lock(&_addLock); - while (!_rayPicksToAdd.isEmpty()) { - QPair> rayPickToAdd = _rayPicksToAdd.dequeue(); + WriteLock lock(_addLock); + while (!_rayPicksToAdd.empty()) { + std::pair> rayPickToAdd = _rayPicksToAdd.front(); + _rayPicksToAdd.pop(); _rayPicks[rayPickToAdd.first] = rayPickToAdd.second; - _rayPickLocks[rayPickToAdd.first] = std::make_shared(); + _rayPickLocks[rayPickToAdd.first] = std::make_shared(); } } { - QWriteLocker lock(&_removeLock); - while (!_rayPicksToRemove.isEmpty()) { - QUuid uid = _rayPicksToRemove.dequeue(); + WriteLock lock(_removeLock); + while (!_rayPicksToRemove.empty()) { + QUuid uid = _rayPicksToRemove.front(); + _rayPicksToRemove.pop(); _rayPicks.remove(uid); _rayPickLocks.remove(uid); } @@ -145,9 +147,9 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { enabled = rayProps["enabled"].toBool(); } - uint16_t filter = 0; + RayPickFilter filter = RayPickFilter(); if (rayProps["filter"].isValid()) { - filter = rayProps["filter"].toUInt(); + filter = RayPickFilter(rayProps["filter"].toUInt()); } float maxDistance = 0.0f; @@ -156,7 +158,7 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { } if (rayProps["joint"].isValid()) { - QString jointName = rayProps["joint"].toString(); + std::string jointName = rayProps["joint"].toString().toStdString(); if (jointName != "Mouse") { // x = upward, y = forward, z = lateral @@ -170,14 +172,14 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { dirOffset = vec3FromVariant(rayProps["dirOffset"]); } - QWriteLocker lock(&_addLock); + WriteLock lock(_addLock); QUuid id = QUuid::createUuid(); - _rayPicksToAdd.enqueue(QPair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); + _rayPicksToAdd.push(std::pair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); return id; } else { - QWriteLocker lock(&_addLock); + WriteLock lock(_addLock); QUuid id = QUuid::createUuid(); - _rayPicksToAdd.enqueue(QPair>(id, std::make_shared(filter, maxDistance, enabled))); + _rayPicksToAdd.push(std::pair>(id, std::make_shared(filter, maxDistance, enabled))); return id; } } else if (rayProps["position"].isValid()) { @@ -188,9 +190,9 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { direction = vec3FromVariant(rayProps["direction"]); } - QWriteLocker lock(&_addLock); + WriteLock lock(_addLock); QUuid id = QUuid::createUuid(); - _rayPicksToAdd.enqueue(QPair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); + _rayPicksToAdd.push(std::pair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); return id; } @@ -198,28 +200,28 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { } void RayPickManager::removeRayPick(const QUuid uid) { - QWriteLocker lock(&_removeLock); - _rayPicksToRemove.enqueue(uid); + WriteLock lock(_removeLock); + _rayPicksToRemove.push(uid); } void RayPickManager::enableRayPick(const QUuid uid) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker rayPickLock(_rayPickLocks[uid].get()); + WriteLock rayPickLock(*_rayPickLocks[uid]); _rayPicks[uid]->enable(); } } void RayPickManager::disableRayPick(const QUuid uid) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker rayPickLock(_rayPickLocks[uid].get()); + WriteLock rayPickLock(*_rayPickLocks[uid]); _rayPicks[uid]->disable(); } } const PickRay RayPickManager::getPickRay(const QUuid uid) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { bool valid; PickRay pickRay = _rayPicks[uid]->getPickRay(valid); @@ -231,58 +233,58 @@ const PickRay RayPickManager::getPickRay(const QUuid uid) { } const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QReadLocker lock(_rayPickLocks[uid].get()); + ReadLock lock(*_rayPickLocks[uid]); return _rayPicks[uid]->getPrevRayPickResult(); } return RayPickResult(); } void RayPickManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); _rayPicks[uid]->setIgnoreEntities(ignoreEntities); } } void RayPickManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); _rayPicks[uid]->setIncludeEntities(includeEntities); } } void RayPickManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); _rayPicks[uid]->setIgnoreOverlays(ignoreOverlays); } } void RayPickManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); _rayPicks[uid]->setIncludeOverlays(includeOverlays); } } void RayPickManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); _rayPicks[uid]->setIgnoreAvatars(ignoreAvatars); } } void RayPickManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { - QReadLocker containsLock(&_containsLock); + ReadLock containsLock(_containsLock); if (_rayPicks.contains(uid)) { - QWriteLocker lock(_rayPickLocks[uid].get()); + WriteLock lock(*_rayPickLocks[uid]); _rayPicks[uid]->setIncludeAvatars(includeAvatars); } } \ No newline at end of file diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 592541e7cf..9055e060ef 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -11,35 +11,20 @@ #ifndef hifi_RayPickManager_h #define hifi_RayPickManager_h -#include -#include -#include +#include "RayPick.h" + #include +#include #include #include "RegisteredMetaTypes.h" #include "DependencyManager.h" -class RayPick; +#include +#include + class RayPickResult; -enum RayPickMask { - PICK_NOTHING = 0, - PICK_ENTITIES = 1 << 0, - PICK_OVERLAYS = 1 << 1, - PICK_AVATARS = 1 << 2, - PICK_HUD = 1 << 3, - - // NOT YET IMPLEMENTED - PICK_BOUNDING_BOX = 1 << 4, // if not set, picks again physics mesh (can't pick against graphics mesh, yet) - - PICK_INCLUDE_INVISIBLE = 1 << 5, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements - PICK_INCLUDE_NONCOLLIDABLE = 1 << 6, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements - - // NOT YET IMPLEMENTED - PICK_ALL_INTERSECTIONS = 1 << 7 // if not set, returns closest intersection, otherwise, returns list of all intersections -}; - class RayPickManager : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) @@ -78,34 +63,37 @@ public slots: private: QHash> _rayPicks; - QHash> _rayPickLocks; - QReadWriteLock _addLock; - QQueue>> _rayPicksToAdd; - QReadWriteLock _removeLock; - QQueue _rayPicksToRemove; - QReadWriteLock _containsLock; + QHash> _rayPickLocks; + std::shared_mutex _addLock; + std::queue>> _rayPicksToAdd; + std::shared_mutex _removeLock; + std::queue _rayPicksToRemove; + std::shared_mutex _containsLock; - typedef QHash, QHash> RayPickCache; + typedef QHash, std::unordered_map> RayPickCache; // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer - bool checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, unsigned int mask); - void cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, QPair& ray, RayPickCache& cache); + bool checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayPickFilter::Flags& mask); + void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayPickFilter::Flags& mask, RayPickResult& res, QPair& ray, RayPickCache& cache); - unsigned int PICK_NOTHING() { return RayPickMask::PICK_NOTHING; } - unsigned int PICK_ENTITIES() { return RayPickMask::PICK_ENTITIES; } - unsigned int PICK_OVERLAYS() { return RayPickMask::PICK_OVERLAYS; } - unsigned int PICK_AVATARS() { return RayPickMask::PICK_AVATARS; } - unsigned int PICK_HUD() { return RayPickMask::PICK_HUD; } - unsigned int PICK_BOUNDING_BOX() { return RayPickMask::PICK_BOUNDING_BOX; } - unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickMask::PICK_INCLUDE_INVISIBLE; } - unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickMask::PICK_INCLUDE_NONCOLLIDABLE; } - unsigned int PICK_ALL_INTERSECTIONS() { return RayPickMask::PICK_ALL_INTERSECTIONS; } + unsigned int PICK_NOTHING() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_NOTHING); } + unsigned int PICK_ENTITIES() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ENTITIES); } + unsigned int PICK_OVERLAYS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_OVERLAYS); } + unsigned int PICK_AVATARS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_AVATARS); } + unsigned int PICK_HUD() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_HUD); } + unsigned int PICK_BOUNDING_BOX() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COURSE); } + unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } + unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } + unsigned int PICK_ALL_INTERSECTIONS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } + typedef std::lock_guard WriteLock; + typedef std::shared_lock ReadLock; + }; #endif // hifi_RayPickManager_h \ No newline at end of file diff --git a/interface/src/raypick/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp index 43088150ad..89bcddb3df 100644 --- a/interface/src/raypick/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -10,7 +10,7 @@ // #include "StaticRayPick.h" -StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance, const bool enabled) : +StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _pickRay(position, direction) { diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index 05ff4ef397..fc09ee6a27 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -16,7 +16,7 @@ class StaticRayPick : public RayPick { public: - StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const uint16_t filter, const float maxDistance = 0.0f, const bool enabled = false); + StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); const PickRay getPickRay(bool& valid) const override; From 96b179386fcc506454706a95d38550aa7abafcc0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 28 Jul 2017 16:56:07 -0700 Subject: [PATCH 63/95] working on fixing non-AA overlays --- interface/src/ui/overlays/OverlaysPayload.cpp | 8 ++--- .../render-utils/src/AntialiasingEffect.cpp | 1 + libraries/render-utils/src/GeometryCache.cpp | 19 ++++++------ libraries/render-utils/src/GeometryCache.h | 5 --- .../render-utils/src/RenderDeferredTask.cpp | 28 ++++++++++------- .../render-utils/src/StencilMaskPass.cpp | 4 +++ libraries/render-utils/src/StencilMaskPass.h | 1 + libraries/render-utils/src/simple.slv | 3 +- .../src/simple_opaque_web_browser_overlay.slf | 30 ------------------ ...simple_transparent_web_browser_overlay.slf | 31 ------------------- libraries/render/src/render/FilterTask.cpp | 17 +++++++++- libraries/render/src/render/FilterTask.h | 15 +++++++++ 12 files changed, 66 insertions(+), 96 deletions(-) delete mode 100644 libraries/render-utils/src/simple_opaque_web_browser_overlay.slf delete mode 100644 libraries/render-utils/src/simple_transparent_web_browser_overlay.slf diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index d14805c1ba..34b7d29b0d 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -37,9 +37,6 @@ namespace render { if (std::static_pointer_cast(overlay)->getDrawInFront()) { builder.withLayered(); } - if (!std::static_pointer_cast(overlay)->isAA()) { - builder.withLayered(); - } if (overlay->getAlphaPulse() != 0.0f || overlay->getAlpha() != 1.0f) { builder.withTransparent(); } @@ -60,14 +57,15 @@ namespace render { if (overlay->is3D()) { auto overlay3D = std::dynamic_pointer_cast(overlay); - if (overlay3D->isAA()) + if (overlay3D->isAA()) { if (overlay3D->getDrawInFront()) { return LAYER_3D_FRONT; } else { return LAYER_3D; } - else + } else { return LAYER_NO_AA; + } } else { return LAYER_2D; } diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 55a46a526f..f4d2bc5e40 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -131,6 +131,7 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const // FXAA step auto pipeline = getAntialiasingPipeline(renderContext->args); + _antialiasingBuffer->setDepthStencilBuffer(sourceBuffer->getDepthStencilBuffer(), sourceBuffer->getDepthStencilBufferFormat()); batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0)); batch.setFramebuffer(_antialiasingBuffer); batch.setPipeline(pipeline); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 5f2acff16f..60b0bd8adb 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -38,9 +38,7 @@ #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" #include "simple_opaque_web_browser_frag.h" -#include "simple_opaque_web_browser_overlay_frag.h" #include "simple_transparent_web_browser_frag.h" -#include "simple_transparent_web_browser_overlay_frag.h" #include "glowLine_vert.h" #include "glowLine_frag.h" @@ -1814,7 +1812,7 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { return a.getRaw() == b.getRaw(); } -static void buildWebShader(const std::string& vertShaderText, const std::string& fragShaderText, bool blendEnable, +static void buildWebShader(const std::string& vertShaderText, const std::string& fragShaderText, bool blendEnable, bool isAA, gpu::ShaderPointer& shaderPointerOut, gpu::PipelinePointer& pipelinePointerOut) { auto VS = gpu::Shader::createVertex(vertShaderText); auto PS = gpu::Shader::createPixel(fragShaderText); @@ -1835,6 +1833,10 @@ static void buildWebShader(const std::string& vertShaderText, const std::string& PrepareStencil::testMaskDrawShape(*state); } + if (!isAA) { + PrepareStencil::drawMaskDepth(*state); + } + pipelinePointerOut = gpu::Pipeline::create(shaderPointerOut, state); } @@ -1846,11 +1848,10 @@ gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram(bool isAA) { static std::once_flag once; std::call_once(once, [&]() { const bool BLEND_ENABLE = false; - buildWebShader(simple_vert, simple_opaque_web_browser_frag, BLEND_ENABLE, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipeline); - buildWebShader(simple_vert, simple_opaque_web_browser_overlay_frag, BLEND_ENABLE, _simpleOpaqueWebBrowserOverlayShader, _simpleOpaqueWebBrowserOverlayPipeline); + buildWebShader(simple_vert, simple_opaque_web_browser_frag, BLEND_ENABLE, isAA, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipeline); }); - return isAA ? _simpleOpaqueWebBrowserPipeline : _simpleOpaqueWebBrowserOverlayPipeline; + return _simpleOpaqueWebBrowserPipeline; } void GeometryCache::bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isAA) { @@ -1860,13 +1861,11 @@ void GeometryCache::bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isA gpu::PipelinePointer GeometryCache::getTransparentWebBrowserProgram(bool isAA) { static std::once_flag once; std::call_once(once, [&]() { - const bool BLEND_ENABLE = true; - buildWebShader(simple_vert, simple_transparent_web_browser_frag, BLEND_ENABLE, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipeline); - buildWebShader(simple_vert, simple_transparent_web_browser_overlay_frag, BLEND_ENABLE, _simpleTransparentWebBrowserOverlayShader, _simpleTransparentWebBrowserOverlayPipeline); + buildWebShader(simple_vert, simple_transparent_web_browser_frag, BLEND_ENABLE, isAA, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipeline); }); - return isAA ? _simpleTransparentWebBrowserPipeline : _simpleTransparentWebBrowserOverlayPipeline; + return _simpleTransparentWebBrowserPipeline; } void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index fa558a1151..69759b311e 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -430,11 +430,6 @@ private: gpu::PipelinePointer _simpleOpaqueWebBrowserPipeline; gpu::ShaderPointer _simpleTransparentWebBrowserShader; gpu::PipelinePointer _simpleTransparentWebBrowserPipeline; - - gpu::ShaderPointer _simpleOpaqueWebBrowserOverlayShader; - gpu::PipelinePointer _simpleOpaqueWebBrowserOverlayPipeline; - gpu::ShaderPointer _simpleTransparentWebBrowserOverlayShader; - gpu::PipelinePointer _simpleTransparentWebBrowserOverlayPipeline; }; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 20c999019b..547e9de5b8 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -66,7 +66,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Filter the non antialiaased overlays const int LAYER_NO_AA = 3; - const auto nonAAOverlays = task.addJob("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA); + const auto overlaysOpaqueAA = task.addJob("FilterAAOverlaysOpaque", overlayOpaques, LAYER_NO_AA); + const auto overlaysOpaqueNonAA = task.addJob("FilterNonAAOverlaysOpaque", overlayOpaques, LAYER_NO_AA); + const auto overlaysTransparentAA = task.addJob("FilterAAOverlaysTransparent", overlayTransparents, LAYER_NO_AA); + const auto overlaysTransparentNonAA = task.addJob("FilterNonAAOverlaysTransparent", overlayTransparents, LAYER_NO_AA); // Prepare deferred, generate the shared Deferred Frame Transform const auto deferredFrameTransform = task.addJob("DeferredFrameTransform"); @@ -164,14 +167,20 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren } // Overlays - const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying(); - const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying(); - task.addJob("DrawOverlay3DOpaque", overlayOpaquesInputs, true); - task.addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); + const auto overlaysOpaqueAAInputs = DrawOverlay3D::Inputs(overlaysOpaqueAA, lightingModel).hasVarying(); + const auto overlaysOpaqueNonAAInputs = DrawOverlay3D::Inputs(overlaysOpaqueNonAA, lightingModel).hasVarying(); + const auto overlaysTransparentAAInputs = DrawOverlay3D::Inputs(overlaysTransparentAA, lightingModel).hasVarying(); + const auto overlaysTransparentNonAAInputs = DrawOverlay3D::Inputs(overlaysTransparentNonAA, lightingModel).hasVarying(); + task.addJob("DrawOverlay3DOpaqueAA", overlaysOpaqueAAInputs, true); + task.addJob("DrawOverlay3DOpaqueNonAA", overlaysOpaqueNonAAInputs, true); + task.addJob("DrawOverlay3DTransparentAA", overlaysTransparentAAInputs, false); + task.addJob("DrawOverlay3DTransparentNonAA", overlaysTransparentNonAAInputs, false); { // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer - task.addJob("DrawOverlayOpaqueBounds", overlayOpaques); - task.addJob("DrawOverlayTransparentBounds", overlayTransparents); + task.addJob("DrawOverlayOpaqueBounds", overlaysOpaqueAA); + task.addJob("DrawOverlayOpaqueNonAABounds", overlaysOpaqueNonAA); + task.addJob("DrawOverlayTransparentAABounds", overlaysTransparentAA); + task.addJob("DrawOverlayTransparentNonAABounds", overlaysTransparentNonAA); } // Debugging stages @@ -204,14 +213,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawZoneStack", deferredFrameTransform); } - // AA job to be revisited task.addJob("Antialiasing", primaryFramebuffer); - // Draw 2DWeb non AA - const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying(); - task.addJob("Draw2DWebSurfaces", nonAAOverlaysInputs, false); - task.addJob("ToneAndPostRangeTimer", toneAndPostRangeTimer); // Blit! diff --git a/libraries/render-utils/src/StencilMaskPass.cpp b/libraries/render-utils/src/StencilMaskPass.cpp index 2d4efc0573..59e4cc6e59 100644 --- a/libraries/render-utils/src/StencilMaskPass.cpp +++ b/libraries/render-utils/src/StencilMaskPass.cpp @@ -108,6 +108,10 @@ void PrepareStencil::drawMask(gpu::State& state) { state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE)); } +void PrepareStencil::drawMaskDepth(gpu::State& state) { + state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); +} + void PrepareStencil::testMask(gpu::State& state) { state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); } diff --git a/libraries/render-utils/src/StencilMaskPass.h b/libraries/render-utils/src/StencilMaskPass.h index 01601d1ae6..19224369ff 100644 --- a/libraries/render-utils/src/StencilMaskPass.h +++ b/libraries/render-utils/src/StencilMaskPass.h @@ -47,6 +47,7 @@ public: static void drawMask(gpu::State& state); + static void drawMaskDepth(gpu::State& state); static void testMask(gpu::State& state); static void testBackground(gpu::State& state); static void testMaskDrawShape(gpu::State& state); diff --git a/libraries/render-utils/src/simple.slv b/libraries/render-utils/src/simple.slv index 64d3e24192..c9fa761ebc 100644 --- a/libraries/render-utils/src/simple.slv +++ b/libraries/render-utils/src/simple.slv @@ -27,12 +27,11 @@ out vec4 _position; void main(void) { _color = colorToLinearRGBA(inColor); _texCoord0 = inTexCoord0.st; - _position = inPosition; _modelNormal = inNormal.xyz; // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> } \ No newline at end of file diff --git a/libraries/render-utils/src/simple_opaque_web_browser_overlay.slf b/libraries/render-utils/src/simple_opaque_web_browser_overlay.slf deleted file mode 100644 index 6d4d35591f..0000000000 --- a/libraries/render-utils/src/simple_opaque_web_browser_overlay.slf +++ /dev/null @@ -1,30 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple_opaque_web_browser_overlay.slf -// fragment shader -// -// Created by Anthony Thibault on 1/30/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 -// -// Same as simple_opaque_web_browser.slf except frame buffer is sRGB, so colorToLinearRGBA is not necessary. - -<@include gpu/Color.slh@> -<@include DeferredBufferWrite.slh@> - -// the albedo texture -uniform sampler2D originalTexture; - -// the interpolated normal -in vec3 _normal; -in vec4 _color; -in vec2 _texCoord0; - -void main(void) { - vec4 texel = texture(originalTexture, _texCoord0.st); - _fragColor0 = vec4(_color.rgb * texel.rgb, 1.0); -} diff --git a/libraries/render-utils/src/simple_transparent_web_browser_overlay.slf b/libraries/render-utils/src/simple_transparent_web_browser_overlay.slf deleted file mode 100644 index af52389d5b..0000000000 --- a/libraries/render-utils/src/simple_transparent_web_browser_overlay.slf +++ /dev/null @@ -1,31 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple_transparent_web_browser_overlay.slf -// fragment shader -// -// Created by Anthony Thibault on 1/30/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 -// -// Same as simple_transparent_web_browser.slf except frame buffer is sRGB, So colorToLinearRGBA is not necessary. -// - -<@include gpu/Color.slh@> -<@include DeferredBufferWrite.slh@> - -// the albedo texture -uniform sampler2D originalTexture; - -// the interpolated normal -in vec3 _normal; -in vec4 _color; -in vec2 _texCoord0; - -void main(void) { - vec4 texel = texture(originalTexture, _texCoord0.st); - _fragColor0 = vec4(_color.rgb * texel.rgb, _color.a); -} diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index f6b765cd9d..fe3aea94f6 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -27,7 +27,7 @@ void FilterLayeredItems::run(const RenderContextPointer& renderContext, const It // Clear previous values outItems.clear(); - // For each item, filter it into one bucket + // Filter matches into one bucket for (auto itemBound : inItems) { auto& item = scene->getItem(itemBound.id); if (item.getLayer() == _keepLayer) { @@ -36,6 +36,21 @@ void FilterLayeredItems::run(const RenderContextPointer& renderContext, const It } } +void FilterOutLayeredItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { + auto& scene = renderContext->_scene; + + // Clear previous values + outItems.clear(); + + // Filter non-matches into one bucket + for (auto itemBound : inItems) { + auto& item = scene->getItem(itemBound.id); + if (item.getLayer() != _removeLayer) { + outItems.emplace_back(itemBound); + } + } +} + void SliceItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { outItems.clear(); std::static_pointer_cast(renderContext->jobConfig)->setNumItems((int)inItems.size()); diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h index 1c4611ee9f..19883e03cd 100644 --- a/libraries/render/src/render/FilterTask.h +++ b/libraries/render/src/render/FilterTask.h @@ -76,6 +76,21 @@ namespace render { void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); }; + // Filter the items not belonging to the job's remove layer + class FilterOutLayeredItems { + public: + using JobModel = Job::ModelIO; + + FilterOutLayeredItems() {} + FilterOutLayeredItems(int removeLayer) : + _removeLayer(removeLayer) { + } + + int _removeLayer { 0 }; + + void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); + }; + // SliceItems job config defining the slice range class SliceItemsConfig : public Job::Config { Q_OBJECT From 353a3e8c682ab2151271648b9246c1f509120813 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 9 Aug 2017 18:04:23 -0700 Subject: [PATCH 64/95] properly fix AA stenciling --- interface/src/ui/overlays/OverlaysPayload.cpp | 11 ++----- .../render-utils/src/AntialiasingEffect.cpp | 6 ++-- libraries/render-utils/src/GeometryCache.cpp | 23 +++++++------- libraries/render-utils/src/GeometryCache.h | 2 ++ .../render-utils/src/RenderDeferredTask.cpp | 31 ++++++------------- .../render-utils/src/RenderDeferredTask.h | 2 +- .../render-utils/src/StencilMaskPass.cpp | 12 ++++--- libraries/render-utils/src/StencilMaskPass.h | 8 +++-- libraries/render-utils/src/simple.slv | 3 +- libraries/render/src/render/FilterTask.cpp | 30 ------------------ libraries/render/src/render/FilterTask.h | 29 ----------------- 11 files changed, 43 insertions(+), 114 deletions(-) diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 34b7d29b0d..8b7100205a 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -50,21 +50,16 @@ namespace render { } template <> int payloadGetLayer(const Overlay::Pointer& overlay) { // Magic number while we are defining the layering mechanism: - const int LAYER_NO_AA = 3; const int LAYER_2D = 2; const int LAYER_3D_FRONT = 1; const int LAYER_3D = 0; if (overlay->is3D()) { auto overlay3D = std::dynamic_pointer_cast(overlay); - if (overlay3D->isAA()) { - if (overlay3D->getDrawInFront()) { - return LAYER_3D_FRONT; - } else { - return LAYER_3D; - } + if (overlay3D->getDrawInFront()) { + return LAYER_3D_FRONT; } else { - return LAYER_NO_AA; + return LAYER_3D; } } else { return LAYER_2D; diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index f4d2bc5e40..3013ad9ebb 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -70,7 +70,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* ar gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - PrepareStencil::testMask(*state); + PrepareStencil::testMaskNoAA(*state); state->setDepthTest(false, false, gpu::LESS_EQUAL); @@ -95,7 +95,7 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(false, false, gpu::LESS_EQUAL); - PrepareStencil::testMask(*state); + PrepareStencil::testMaskNoAA(*state); // Good to go add the brand new pipeline _blendPipeline = gpu::Pipeline::create(program, state); @@ -131,7 +131,6 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const // FXAA step auto pipeline = getAntialiasingPipeline(renderContext->args); - _antialiasingBuffer->setDepthStencilBuffer(sourceBuffer->getDepthStencilBuffer(), sourceBuffer->getDepthStencilBufferFormat()); batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0)); batch.setFramebuffer(_antialiasingBuffer); batch.setPipeline(pipeline); @@ -160,7 +159,6 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const // Blend step - getBlendPipeline(); batch.setResourceTexture(0, _antialiasingTexture); batch.setFramebuffer(sourceBuffer); batch.setPipeline(getBlendPipeline()); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 60b0bd8adb..3f43d3173f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1718,7 +1718,7 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { auto stateNoBlend = std::make_shared(); - PrepareStencil::testMaskDrawShape(*state); + PrepareStencil::testMaskDrawShape(*stateNoBlend); auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); @@ -1827,14 +1827,11 @@ static void buildWebShader(const std::string& vertShaderText, const std::string& state->setBlendFunction(blendEnable, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - if (blendEnable) { - PrepareStencil::testMask(*state); - } else { - PrepareStencil::testMaskDrawShape(*state); - } - if (!isAA) { - PrepareStencil::drawMaskDepth(*state); + if (isAA) { + blendEnable ? PrepareStencil::testMask(*state) : PrepareStencil::testMaskDrawShape(*state); + } else { + PrepareStencil::testMaskDrawShapeNoAA(*state); } pipelinePointerOut = gpu::Pipeline::create(shaderPointerOut, state); @@ -1848,10 +1845,11 @@ gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram(bool isAA) { static std::once_flag once; std::call_once(once, [&]() { const bool BLEND_ENABLE = false; - buildWebShader(simple_vert, simple_opaque_web_browser_frag, BLEND_ENABLE, isAA, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipeline); + buildWebShader(simple_vert, simple_opaque_web_browser_frag, BLEND_ENABLE, true, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipeline); + buildWebShader(simple_vert, simple_opaque_web_browser_frag, BLEND_ENABLE, false, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipelineNoAA); }); - return _simpleOpaqueWebBrowserPipeline; + return isAA ? _simpleOpaqueWebBrowserPipeline : _simpleOpaqueWebBrowserPipelineNoAA; } void GeometryCache::bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isAA) { @@ -1862,10 +1860,11 @@ gpu::PipelinePointer GeometryCache::getTransparentWebBrowserProgram(bool isAA) { static std::once_flag once; std::call_once(once, [&]() { const bool BLEND_ENABLE = true; - buildWebShader(simple_vert, simple_transparent_web_browser_frag, BLEND_ENABLE, isAA, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipeline); + buildWebShader(simple_vert, simple_transparent_web_browser_frag, BLEND_ENABLE, true, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipeline); + buildWebShader(simple_vert, simple_transparent_web_browser_frag, BLEND_ENABLE, false, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipelineNoAA); }); - return _simpleTransparentWebBrowserPipeline; + return isAA ? _simpleTransparentWebBrowserPipeline : _simpleTransparentWebBrowserPipelineNoAA; } void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 69759b311e..77effc8969 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -428,8 +428,10 @@ private: gpu::ShaderPointer _simpleOpaqueWebBrowserShader; gpu::PipelinePointer _simpleOpaqueWebBrowserPipeline; + gpu::PipelinePointer _simpleOpaqueWebBrowserPipelineNoAA; gpu::ShaderPointer _simpleTransparentWebBrowserShader; gpu::PipelinePointer _simpleTransparentWebBrowserPipeline; + gpu::PipelinePointer _simpleTransparentWebBrowserPipelineNoAA; }; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 547e9de5b8..27d2b54121 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -64,13 +64,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto background = items[RenderFetchCullSortTask::BACKGROUND]; const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; - // Filter the non antialiaased overlays - const int LAYER_NO_AA = 3; - const auto overlaysOpaqueAA = task.addJob("FilterAAOverlaysOpaque", overlayOpaques, LAYER_NO_AA); - const auto overlaysOpaqueNonAA = task.addJob("FilterNonAAOverlaysOpaque", overlayOpaques, LAYER_NO_AA); - const auto overlaysTransparentAA = task.addJob("FilterAAOverlaysTransparent", overlayTransparents, LAYER_NO_AA); - const auto overlaysTransparentNonAA = task.addJob("FilterNonAAOverlaysTransparent", overlayTransparents, LAYER_NO_AA); - // Prepare deferred, generate the shared Deferred Frame Transform const auto deferredFrameTransform = task.addJob("DeferredFrameTransform"); const auto lightingModel = task.addJob("LightingModel"); @@ -157,7 +150,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer)); task.addJob("ToneMapping", toneMappingInputs); - { // DEbug the bounds of the rendered items, still look at the zbuffer + { // Debug the bounds of the rendered items, still look at the zbuffer task.addJob("DrawMetaBounds", metas); task.addJob("DrawOpaqueBounds", opaques); task.addJob("DrawTransparentBounds", transparents); @@ -167,22 +160,16 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren } // Overlays - const auto overlaysOpaqueAAInputs = DrawOverlay3D::Inputs(overlaysOpaqueAA, lightingModel).hasVarying(); - const auto overlaysOpaqueNonAAInputs = DrawOverlay3D::Inputs(overlaysOpaqueNonAA, lightingModel).hasVarying(); - const auto overlaysTransparentAAInputs = DrawOverlay3D::Inputs(overlaysTransparentAA, lightingModel).hasVarying(); - const auto overlaysTransparentNonAAInputs = DrawOverlay3D::Inputs(overlaysTransparentNonAA, lightingModel).hasVarying(); - task.addJob("DrawOverlay3DOpaqueAA", overlaysOpaqueAAInputs, true); - task.addJob("DrawOverlay3DOpaqueNonAA", overlaysOpaqueNonAAInputs, true); - task.addJob("DrawOverlay3DTransparentAA", overlaysTransparentAAInputs, false); - task.addJob("DrawOverlay3DTransparentNonAA", overlaysTransparentNonAAInputs, false); + const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying(); + const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying(); + task.addJob("DrawOverlay3DOpaque", overlayOpaquesInputs, true); + task.addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); - { // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer - task.addJob("DrawOverlayOpaqueBounds", overlaysOpaqueAA); - task.addJob("DrawOverlayOpaqueNonAABounds", overlaysOpaqueNonAA); - task.addJob("DrawOverlayTransparentAABounds", overlaysTransparentAA); - task.addJob("DrawOverlayTransparentNonAABounds", overlaysTransparentNonAA); + { // Debug the bounds of the rendered Overlay items, still look at the zbuffer + task.addJob("DrawOverlayOpaqueBounds", overlayOpaques); + task.addJob("DrawOverlayTransparentBounds", overlayTransparents); } - + // Debugging stages { // Debugging Deferred buffer job diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index fd7c5eb23b..dccd539229 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -153,7 +153,7 @@ public: protected: render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config - bool _opaquePass{ true }; + bool _opaquePass { true }; }; class Blit { diff --git a/libraries/render-utils/src/StencilMaskPass.cpp b/libraries/render-utils/src/StencilMaskPass.cpp index 59e4cc6e59..295e124ed1 100644 --- a/libraries/render-utils/src/StencilMaskPass.cpp +++ b/libraries/render-utils/src/StencilMaskPass.cpp @@ -108,14 +108,14 @@ void PrepareStencil::drawMask(gpu::State& state) { state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE)); } -void PrepareStencil::drawMaskDepth(gpu::State& state) { - state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); -} - void PrepareStencil::testMask(gpu::State& state) { state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); } +void PrepareStencil::testMaskNoAA(gpu::State& state) { + state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK | PrepareStencil::STENCIL_NO_AA, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); +} + void PrepareStencil::testBackground(gpu::State& state) { state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_BACKGROUND, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); } @@ -124,6 +124,10 @@ void PrepareStencil::testMaskDrawShape(gpu::State& state) { state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO)); } +void PrepareStencil::testMaskDrawShapeNoAA(gpu::State& state) { + state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK | PrepareStencil::STENCIL_NO_AA, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); +} + void PrepareStencil::testShape(gpu::State& state) { state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_SHAPE, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); } \ No newline at end of file diff --git a/libraries/render-utils/src/StencilMaskPass.h b/libraries/render-utils/src/StencilMaskPass.h index 19224369ff..2c0294c471 100644 --- a/libraries/render-utils/src/StencilMaskPass.h +++ b/libraries/render-utils/src/StencilMaskPass.h @@ -41,16 +41,18 @@ public: void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& dstFramebuffer); - static const gpu::int8 STENCIL_MASK = 2; - static const gpu::int8 STENCIL_BACKGROUND = 1; static const gpu::int8 STENCIL_SHAPE = 0; + static const gpu::int8 STENCIL_BACKGROUND = 1 << 0; + static const gpu::int8 STENCIL_MASK = 1 << 1; + static const gpu::int8 STENCIL_NO_AA = 1 << 2; static void drawMask(gpu::State& state); - static void drawMaskDepth(gpu::State& state); static void testMask(gpu::State& state); + static void testMaskNoAA(gpu::State& state); static void testBackground(gpu::State& state); static void testMaskDrawShape(gpu::State& state); + static void testMaskDrawShapeNoAA(gpu::State& state); static void testShape(gpu::State& state); diff --git a/libraries/render-utils/src/simple.slv b/libraries/render-utils/src/simple.slv index c9fa761ebc..64d3e24192 100644 --- a/libraries/render-utils/src/simple.slv +++ b/libraries/render-utils/src/simple.slv @@ -27,11 +27,12 @@ out vec4 _position; void main(void) { _color = colorToLinearRGBA(inColor); _texCoord0 = inTexCoord0.st; + _position = inPosition; _modelNormal = inNormal.xyz; // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> } \ No newline at end of file diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index fe3aea94f6..252006c6e7 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -21,36 +21,6 @@ using namespace render; -void FilterLayeredItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { - auto& scene = renderContext->_scene; - - // Clear previous values - outItems.clear(); - - // Filter matches into one bucket - for (auto itemBound : inItems) { - auto& item = scene->getItem(itemBound.id); - if (item.getLayer() == _keepLayer) { - outItems.emplace_back(itemBound); - } - } -} - -void FilterOutLayeredItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { - auto& scene = renderContext->_scene; - - // Clear previous values - outItems.clear(); - - // Filter non-matches into one bucket - for (auto itemBound : inItems) { - auto& item = scene->getItem(itemBound.id); - if (item.getLayer() != _removeLayer) { - outItems.emplace_back(itemBound); - } - } -} - void SliceItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { outItems.clear(); std::static_pointer_cast(renderContext->jobConfig)->setNumItems((int)inItems.size()); diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h index 19883e03cd..6d30f46485 100644 --- a/libraries/render/src/render/FilterTask.h +++ b/libraries/render/src/render/FilterTask.h @@ -62,35 +62,6 @@ namespace render { } }; - // Filter the items belonging to the job's keep layer - class FilterLayeredItems { - public: - using JobModel = Job::ModelIO; - - FilterLayeredItems() {} - FilterLayeredItems(int keepLayer) : - _keepLayer(keepLayer) {} - - int _keepLayer { 0 }; - - void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); - }; - - // Filter the items not belonging to the job's remove layer - class FilterOutLayeredItems { - public: - using JobModel = Job::ModelIO; - - FilterOutLayeredItems() {} - FilterOutLayeredItems(int removeLayer) : - _removeLayer(removeLayer) { - } - - int _removeLayer { 0 }; - - void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); - }; - // SliceItems job config defining the slice range class SliceItemsConfig : public Job::Config { Q_OBJECT From da5bb03187431111156690788e17ef848a6989d4 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 10 Aug 2017 16:34:37 -0700 Subject: [PATCH 65/95] Trying to add in a back button --- interface/resources/qml/hifi/tablet/TabletRoot.qml | 5 +++++ interface/resources/qml/hifi/tablet/WindowRoot.qml | 5 +++++ libraries/ui/src/ui/TabletScriptingInterface.cpp | 8 ++++++-- libraries/ui/src/ui/TabletScriptingInterface.h | 2 +- scripts/system/marketplaces/blocksApp.js | 4 ++-- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index c7df6ac64f..c89317c93c 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -93,6 +93,11 @@ Item { loader.source = ""; loader.source = "TabletWebView.qml"; } + + function loadTabletWebBase() { + loader.source = ""; + loader.source = "../../controls/TabletWebView.qml"; + } function returnToPreviousApp() { tabletApps.remove(currentApp); diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index fdfcfcf806..0858b46b40 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -42,6 +42,11 @@ Windows.ScrollingWindow { loader.source = "WindowWebView.qml"; } + function loadTabletWebBase() { + loader.source = ""; + loader.source = "../../controls/TabletWebView.qml"; + } + function loadWebUrl(url, injectedJavaScriptUrl) { loader.item.url = url; loader.item.scriptURL = injectedJavaScriptUrl; diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 984d743ebf..1331b47590 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -604,7 +604,7 @@ void TabletProxy::loadWebScreenOnTop(const QVariant& url, const QString& injectJ _state = State::Web; } -void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl) { +void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "gotoWebScreen", Q_ARG(QString, url), Q_ARG(QString, injectedJavaScriptUrl)); return; @@ -619,7 +619,11 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS if (root) { removeButtonsFromHomeScreen(); - QMetaObject::invokeMethod(root, "loadWebBase"); + if (loadOtherBase) { + QMetaObject::invokeMethod(root, "loadTabletWebBase"); + } else { + QMetaObject::invokeMethod(root, "loadWebBase"); + } QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index af38cb9351..822bae839e 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -122,7 +122,7 @@ public: * @param [injectedJavaScriptUrl] {string} optional url to an additional JS script to inject into the web page. */ Q_INVOKABLE void gotoWebScreen(const QString& url); - Q_INVOKABLE void gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl); + Q_INVOKABLE void gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase = false); Q_INVOKABLE void loadQMLSource(const QVariant& path); // FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success); diff --git a/scripts/system/marketplaces/blocksApp.js b/scripts/system/marketplaces/blocksApp.js index 46a102042e..520b3657b9 100644 --- a/scripts/system/marketplaces/blocksApp.js +++ b/scripts/system/marketplaces/blocksApp.js @@ -10,7 +10,7 @@ }); function onClicked() { - tablet.gotoWebScreen(APP_URL); + tablet.gotoWebScreen(APP_URL, "", true); } button.clicked.connect(onClicked); @@ -19,4 +19,4 @@ } Script.scriptEnding.connect(cleanup); -}()); \ No newline at end of file +}()); From 6c2bf633929b86cd723c26ea9d411706782e9ce3 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 10 Aug 2017 17:51:19 -0700 Subject: [PATCH 66/95] Back button works --- interface/resources/qml/controls/TabletWebView.qml | 2 ++ interface/resources/qml/hifi/tablet/TabletRoot.qml | 3 +++ interface/resources/qml/hifi/tablet/WindowRoot.qml | 3 +++ libraries/ui/src/ui/TabletScriptingInterface.cpp | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 0a5a68717e..59728c4157 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -24,6 +24,7 @@ Item { property alias webView: webview property alias profile: webview.profile property bool remove: false + property bool closeButtonVisible: true // Manage own browse history because WebEngineView history is wiped when a new URL is loaded via // onNewViewRequested, e.g., as happens when a social media share button is clicked. @@ -64,6 +65,7 @@ Item { disabledColor: hifi.colors.lightGrayText enabled: true text: "CLOSE" + visible: closeButtonVisible MouseArea { anchors.fill: parent diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index c89317c93c..bbf56c7827 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -126,6 +126,9 @@ Item { loader.item.url = url; loader.item.scriptURL = injectedJavaScriptUrl; tabletApps.append({"appUrl": "TabletWebView.qml", "isWebUrl": true, "scriptUrl": injectedJavaScriptUrl, "appWebUrl": url}); + if (loader.item.hasOwnProperty("closeButtonVisible")) { + loader.item.closeButtonVisible = false; + } } // used to send a message from qml to interface script. diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index 0858b46b40..8596007956 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -50,6 +50,9 @@ Windows.ScrollingWindow { function loadWebUrl(url, injectedJavaScriptUrl) { loader.item.url = url; loader.item.scriptURL = injectedJavaScriptUrl; + if (loader.item.hasOwnProperty("closeButtonVisible")) { + loader.item.closeButtonVisible = false; + } } // used to send a message from qml to interface script. diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 1331b47590..adff219e0f 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -606,7 +606,7 @@ void TabletProxy::loadWebScreenOnTop(const QVariant& url, const QString& injectJ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "gotoWebScreen", Q_ARG(QString, url), Q_ARG(QString, injectedJavaScriptUrl)); + QMetaObject::invokeMethod(this, "gotoWebScreen", Q_ARG(QString, url), Q_ARG(QString, injectedJavaScriptUrl), Q_ARG(bool, loadOtherBase)); return; } From f058781f49c82d97074a797ac35c24ef1b9c7a0e Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 11 Aug 2017 10:07:20 -0700 Subject: [PATCH 67/95] just kidding shared_mutexes are c++17 --- interface/src/raypick/LaserPointerManager.cpp | 62 +++++++++---------- interface/src/raypick/LaserPointerManager.h | 13 ++-- interface/src/raypick/RayPickManager.cpp | 56 ++++++++--------- interface/src/raypick/RayPickManager.h | 13 ++-- 4 files changed, 69 insertions(+), 75 deletions(-) diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index da20068cba..089b9911d0 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -15,7 +15,7 @@ QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); if (!laserPointer->getRayUID().isNull()) { - WriteLock lock(_addLock); + QWriteLocker lock(&_addLock); QUuid id = QUuid::createUuid(); _laserPointersToAdd.push(std::pair>(id, laserPointer)); return id; @@ -24,46 +24,46 @@ QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const } void LaserPointerManager::removeLaserPointer(const QUuid uid) { - WriteLock lock(_removeLock); + QWriteLocker lock(&_removeLock); _laserPointersToRemove.push(uid); } void LaserPointerManager::enableLaserPointer(const QUuid uid) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->enable(); } } void LaserPointerManager::disableLaserPointer(const QUuid uid) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->disable(); } } void LaserPointerManager::setRenderState(QUuid uid, const std::string& renderState) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setRenderState(renderState); } } void LaserPointerManager::editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->editRenderState(state, startProps, pathProps, endProps); } } const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - ReadLock laserLock(*_laserPointerLocks[uid]); + QReadLocker laserLock(_laserPointerLocks[uid].get()); return _laserPointers[uid]->getPrevRayPickResult(); } return RayPickResult(); @@ -72,23 +72,23 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) { void LaserPointerManager::update() { for (QUuid& uid : _laserPointers.keys()) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts - ReadLock laserLock(*_laserPointerLocks[uid]); + QReadLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->update(); } - WriteLock containsLock(_containsLock); + QWriteLocker containsLock(&_containsLock); { - WriteLock lock(_addLock); + QWriteLocker lock(&_addLock); while (!_laserPointersToAdd.empty()) { std::pair> laserPointerToAdd = _laserPointersToAdd.front(); _laserPointersToAdd.pop(); _laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second; - _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); + _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); } } { - WriteLock lock(_removeLock); + QWriteLocker lock(&_removeLock); while (!_laserPointersToRemove.empty()) { QUuid uid = _laserPointersToRemove.front(); _laserPointersToRemove.pop(); @@ -99,57 +99,57 @@ void LaserPointerManager::update() { } void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIgnoreEntities(ignoreEntities); } } void LaserPointerManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeEntities(includeEntities); } } void LaserPointerManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIgnoreOverlays(ignoreOverlays); } } void LaserPointerManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeOverlays(includeOverlays); } } void LaserPointerManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIgnoreAvatars(ignoreAvatars); } } void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setIncludeAvatars(includeAvatars); } } void LaserPointerManager::setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { - ReadLock lock(_containsLock); + QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { - WriteLock laserLock(*_laserPointerLocks[uid]); + QWriteLocker laserLock(_laserPointerLocks[uid].get()); _laserPointers[uid]->setLockEndUUID(objectID, isOverlay); } } diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 5e33ac77d8..b981dde9fb 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -12,8 +12,8 @@ #define hifi_LaserPointerManager_h #include -#include #include +#include #include "LaserPointer.h" @@ -44,15 +44,12 @@ public: private: QHash> _laserPointers; - QHash> _laserPointerLocks; - std::shared_mutex _addLock; + QHash> _laserPointerLocks; + QReadWriteLock _addLock; std::queue>> _laserPointersToAdd; - std::shared_mutex _removeLock; + QReadWriteLock _removeLock; std::queue _laserPointersToRemove; - std::shared_mutex _containsLock; - - typedef std::lock_guard WriteLock; - typedef std::shared_lock ReadLock; + QReadWriteLock _containsLock; }; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 0fe7fdb823..68c850b295 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -111,7 +111,7 @@ void RayPickManager::update() { } } - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { rayPick->setRayPickResult(res); } else { @@ -119,19 +119,19 @@ void RayPickManager::update() { } } - WriteLock containsLock(_containsLock); + QWriteLocker containsLock(&_containsLock); { - WriteLock lock(_addLock); + QWriteLocker lock(&_addLock); while (!_rayPicksToAdd.empty()) { std::pair> rayPickToAdd = _rayPicksToAdd.front(); _rayPicksToAdd.pop(); _rayPicks[rayPickToAdd.first] = rayPickToAdd.second; - _rayPickLocks[rayPickToAdd.first] = std::make_shared(); + _rayPickLocks[rayPickToAdd.first] = std::make_shared(); } } { - WriteLock lock(_removeLock); + QWriteLocker lock(&_removeLock); while (!_rayPicksToRemove.empty()) { QUuid uid = _rayPicksToRemove.front(); _rayPicksToRemove.pop(); @@ -172,12 +172,12 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { dirOffset = vec3FromVariant(rayProps["dirOffset"]); } - WriteLock lock(_addLock); + QWriteLocker lock(&_addLock); QUuid id = QUuid::createUuid(); _rayPicksToAdd.push(std::pair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); return id; } else { - WriteLock lock(_addLock); + QWriteLocker lock(&_addLock); QUuid id = QUuid::createUuid(); _rayPicksToAdd.push(std::pair>(id, std::make_shared(filter, maxDistance, enabled))); return id; @@ -190,7 +190,7 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { direction = vec3FromVariant(rayProps["direction"]); } - WriteLock lock(_addLock); + QWriteLocker lock(&_addLock); QUuid id = QUuid::createUuid(); _rayPicksToAdd.push(std::pair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); return id; @@ -200,28 +200,28 @@ QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { } void RayPickManager::removeRayPick(const QUuid uid) { - WriteLock lock(_removeLock); + QWriteLocker lock(&_removeLock); _rayPicksToRemove.push(uid); } void RayPickManager::enableRayPick(const QUuid uid) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock rayPickLock(*_rayPickLocks[uid]); + QWriteLocker rayPickLock(_rayPickLocks[uid].get()); _rayPicks[uid]->enable(); } } void RayPickManager::disableRayPick(const QUuid uid) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock rayPickLock(*_rayPickLocks[uid]); + QWriteLocker rayPickLock(_rayPickLocks[uid].get()); _rayPicks[uid]->disable(); } } const PickRay RayPickManager::getPickRay(const QUuid uid) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { bool valid; PickRay pickRay = _rayPicks[uid]->getPickRay(valid); @@ -233,58 +233,58 @@ const PickRay RayPickManager::getPickRay(const QUuid uid) { } const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - ReadLock lock(*_rayPickLocks[uid]); + QReadLocker lock(_rayPickLocks[uid].get()); return _rayPicks[uid]->getPrevRayPickResult(); } return RayPickResult(); } void RayPickManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); _rayPicks[uid]->setIgnoreEntities(ignoreEntities); } } void RayPickManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); _rayPicks[uid]->setIncludeEntities(includeEntities); } } void RayPickManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); _rayPicks[uid]->setIgnoreOverlays(ignoreOverlays); } } void RayPickManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); _rayPicks[uid]->setIncludeOverlays(includeOverlays); } } void RayPickManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); _rayPicks[uid]->setIgnoreAvatars(ignoreAvatars); } } void RayPickManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { - ReadLock containsLock(_containsLock); + QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { - WriteLock lock(*_rayPickLocks[uid]); + QWriteLocker lock(_rayPickLocks[uid].get()); _rayPicks[uid]->setIncludeAvatars(includeAvatars); } } \ No newline at end of file diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 9055e060ef..e422995810 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -14,8 +14,8 @@ #include "RayPick.h" #include -#include #include +#include #include "RegisteredMetaTypes.h" #include "DependencyManager.h" @@ -63,12 +63,12 @@ public slots: private: QHash> _rayPicks; - QHash> _rayPickLocks; - std::shared_mutex _addLock; + QHash> _rayPickLocks; + QReadWriteLock _addLock; std::queue>> _rayPicksToAdd; - std::shared_mutex _removeLock; + QReadWriteLock _removeLock; std::queue _rayPicksToRemove; - std::shared_mutex _containsLock; + QReadWriteLock _containsLock; typedef QHash, std::unordered_map> RayPickCache; @@ -91,9 +91,6 @@ private: unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } - typedef std::lock_guard WriteLock; - typedef std::shared_lock ReadLock; - }; #endif // hifi_RayPickManager_h \ No newline at end of file From 92d5a0c55204c1edb231cde553ba45efef088e93 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 14 Aug 2017 11:21:47 +0200 Subject: [PATCH 68/95] Fixed non working fade invert parameter --- libraries/render-utils/src/FadeEffectJobs.cpp | 2 +- libraries/render-utils/src/FadeEffectJobs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index 90459cf0e6..f760276907 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -594,7 +594,7 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou if (update(*jobConfig, scene, transaction, state, deltaTime)) { hasTransaction = true; } - if (isFirstItem) { + if (isFirstItem && jobConfig->manualFade && state.threshold!=jobConfig->threshold) { jobConfig->setProperty("threshold", state.threshold); isFirstItem = false; } diff --git a/libraries/render-utils/src/FadeEffectJobs.h b/libraries/render-utils/src/FadeEffectJobs.h index f827bb6e99..a585d5b98a 100644 --- a/libraries/render-utils/src/FadeEffectJobs.h +++ b/libraries/render-utils/src/FadeEffectJobs.h @@ -50,7 +50,7 @@ class FadeConfig : public render::Job::Config { Q_PROPERTY(float baseSizeY READ getBaseSizeY WRITE setBaseSizeY NOTIFY dirty) Q_PROPERTY(float baseSizeZ READ getBaseSizeZ WRITE setBaseSizeZ NOTIFY dirty) Q_PROPERTY(float baseLevel READ getBaseLevel WRITE setBaseLevel NOTIFY dirty) - Q_PROPERTY(bool _isInverted READ isInverted WRITE setInverted NOTIFY dirty) + Q_PROPERTY(bool isInverted READ isInverted WRITE setInverted NOTIFY dirty) Q_PROPERTY(float noiseSizeX READ getNoiseSizeX WRITE setNoiseSizeX NOTIFY dirty) Q_PROPERTY(float noiseSizeY READ getNoiseSizeY WRITE setNoiseSizeY NOTIFY dirty) Q_PROPERTY(float noiseSizeZ READ getNoiseSizeZ WRITE setNoiseSizeZ NOTIFY dirty) From 358373aeac29957109f0d420e930ff98f34a902c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 14 Aug 2017 11:41:01 +0200 Subject: [PATCH 69/95] Base gradient size edition works again on Elements enter domain event --- libraries/render-utils/src/FadeEffectJobs.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index f760276907..f279f14d12 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -645,9 +645,6 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re { transition.threshold = computeElementEnterRatio(transition.time, eventDuration, timing); transition.baseOffset = transition.noiseOffset; - transition.baseInvSize.x = 1.f / dimensions.x; - transition.baseInvSize.y = 1.f / dimensions.y; - transition.baseInvSize.z = 1.f / dimensions.z; transition.isFinished += (transition.threshold >= 1.f) & 1; if (transition.eventType == render::Transition::ELEMENT_ENTER_DOMAIN) { transition.threshold = 1.f - transition.threshold; From 8d248f5ccd2763859c8964847db37cdcbc567bf1 Mon Sep 17 00:00:00 2001 From: "rick@ghostpunch.com" Date: Mon, 14 Aug 2017 15:59:21 -0400 Subject: [PATCH 70/95] Remove the attempt to determine the maximum width of a PolyLineEntity's strokes using the _strokeWidths[] array, as the values don't seem to correspond with reality. Use a flat 0.075M value for the maxium half of a stroke width instead. --- libraries/entities/src/PolyLineEntityItem.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 4d27330b3e..aa31130c82 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -182,17 +182,9 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { EntityItem::setRegistrationPoint(glm::vec3(0.5f)); return; } - - // Find the max width of the strokes so we can account for that in the size of the bounding box - float maxWidth = 0.0f; - for (int i = 0; i < _strokeWidths.size(); ++i) { - if (_strokeWidths.at(i) > maxWidth) { - maxWidth = _strokeWidths.at(i); - } - } glm::vec3 result; - float halfLineWidth = (maxWidth > 0.0f) ? maxWidth * 0.5f : 0.0f; + const float halfLineWidth = 0.075f; // sadly _strokeWidths() don't seem to correspond to reality, so just use a flat assumption of the stroke width result.x = fabsf(high.x) + fabsf(low.x) + halfLineWidth; result.y = fabsf(high.y) + fabsf(low.y) + halfLineWidth; result.z = fabsf(high.z) + fabsf(low.z) + halfLineWidth; From c88082301e9a8fe8b9df298f807216650748f55c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 14 Aug 2017 22:43:39 +0200 Subject: [PATCH 71/95] Small changes to respect coding rules --- libraries/render-utils/src/FadeEffectJobs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index f279f14d12..d00632c017 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -594,7 +594,7 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou if (update(*jobConfig, scene, transaction, state, deltaTime)) { hasTransaction = true; } - if (isFirstItem && jobConfig->manualFade && state.threshold!=jobConfig->threshold) { + if (isFirstItem && jobConfig->manualFade && (state.threshold != jobConfig->threshold)) { jobConfig->setProperty("threshold", state.threshold); isFirstItem = false; } From 072f3dfb03a203ac546acf631f5bdb484d1213c0 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 15 Aug 2017 10:25:14 -0700 Subject: [PATCH 72/95] removed commented out code, removed blocks from default scripts --- libraries/script-engine/src/FileScriptingInterface.cpp | 1 - scripts/defaultScripts.js | 1 - 2 files changed, 2 deletions(-) diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 681156973b..68a141ad97 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -53,7 +53,6 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool } QStringList fileList = unzipFile(path, tempDir); - //QString filename = QUrl::fromLocalFile(fileList.first()).toString(); if (!fileList.isEmpty()) { qCDebug(scriptengine) << "File to upload: " + fileList.first(); diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index bddb2ae703..2270118861 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -24,7 +24,6 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/makeUserConnection.js", "system/tablet-goto.js", "system/marketplaces/marketplaces.js", - "system/marketplaces/blocksApp.js", // temporarily in default scripts for testing purposes "system/edit.js", "system/notifications.js", "system/dialTone.js", From 9bb7e6685945a9e051af3f2e0cf6dfef6880ff35 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 15 Aug 2017 13:36:41 -0700 Subject: [PATCH 73/95] separate raypickscriptinginterface, cleanup --- interface/src/Application.cpp | 13 ++- interface/src/Application.h | 4 + interface/src/raypick/LaserPointer.cpp | 15 +-- interface/src/raypick/LaserPointer.h | 19 ++-- interface/src/raypick/LaserPointerManager.cpp | 3 +- interface/src/raypick/LaserPointerManager.h | 2 +- .../LaserPointerScriptingInterface.cpp | 5 +- .../raypick/LaserPointerScriptingInterface.h | 3 +- interface/src/raypick/RayPickManager.cpp | 71 +++--------- interface/src/raypick/RayPickManager.h | 60 +++------- .../src/raypick/RayPickScriptingInterface.cpp | 107 ++++++++++++++++++ .../src/raypick/RayPickScriptingInterface.h | 70 ++++++++++++ 12 files changed, 240 insertions(+), 132 deletions(-) create mode 100644 interface/src/raypick/RayPickScriptingInterface.cpp create mode 100644 interface/src/raypick/RayPickScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3d2841923f..750c41d48a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -193,8 +193,9 @@ #include #include #include + +#include #include -#include #include "commerce/Ledger.h" #include "commerce/Wallet.h" @@ -608,7 +609,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set(); return previousSessionCrashed; } @@ -5096,8 +5097,8 @@ void Application::update(float deltaTime) { } { - PROFILE_RANGE(app, "RayPick"); - DependencyManager::get()->update(); + PROFILE_RANGE(app, "RayPickManager"); + _rayPickManager.update(); } { @@ -5965,6 +5966,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AvatarBookmarks", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LocationBookmarks", DependencyManager::get().data()); + + scriptEngine->registerGlobalObject("RayPick", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LaserPointers", DependencyManager::get().data()); // Caches @@ -6019,8 +6022,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("RayPick", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); // connect this script engines printedMessage signal to the global ScriptEngines these various messages diff --git a/interface/src/Application.h b/interface/src/Application.h index fcd47faa41..8a38116fe8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -70,6 +70,8 @@ #include "ui/OverlayConductor.h" #include "ui/overlays/Overlays.h" #include "UndoStackScriptingInterface.h" + +#include "raypick/RayPickManager.h" #include "raypick/LaserPointerManager.h" #include @@ -303,6 +305,7 @@ public: bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } LaserPointerManager& getLaserPointerManager() { return _laserPointerManager; } + RayPickManager& getRayPickManager() { return _rayPickManager; } signals: void svoImportRequested(const QString& url); @@ -702,6 +705,7 @@ private: bool _saveAvatarOverrideUrl { false }; LaserPointerManager _laserPointerManager; + RayPickManager _rayPickManager; }; #endif // hifi_Application_h diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 0e1d384e5d..f4adcc736d 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -11,9 +11,10 @@ #include "LaserPointer.h" #include "Application.h" +#include "ui/overlays/Overlay.h" #include "avatar/AvatarManager.h" -LaserPointer::LaserPointer(const QVariantMap& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, +LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), @@ -22,7 +23,7 @@ LaserPointer::LaserPointer(const QVariantMap& rayProps, const RenderStateMap& re _centerEndY(centerEndY), _lockEnd(lockEnd) { - _rayPickUID = DependencyManager::get()->createRayPick(rayProps); + _rayPickUID = DependencyManager::get()->createRayPick(rayProps); for (auto& state : _renderStates) { if (!enabled || state.first != _currentRenderState) { @@ -37,7 +38,7 @@ LaserPointer::LaserPointer(const QVariantMap& rayProps, const RenderStateMap& re } LaserPointer::~LaserPointer() { - DependencyManager::get()->removeRayPick(_rayPickUID); + DependencyManager::get()->removeRayPick(_rayPickUID); for (auto& renderState : _renderStates) { renderState.second.deleteOverlays(); @@ -48,12 +49,12 @@ LaserPointer::~LaserPointer() { } void LaserPointer::enable() { - DependencyManager::get()->enableRayPick(_rayPickUID); + DependencyManager::get()->enableRayPick(_rayPickUID); _renderingEnabled = true; } void LaserPointer::disable() { - DependencyManager::get()->disableRayPick(_rayPickUID); + DependencyManager::get()->disableRayPick(_rayPickUID); _renderingEnabled = false; if (!_currentRenderState.empty()) { if (_renderStates.find(_currentRenderState) != _renderStates.end()) { @@ -90,7 +91,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState) { - PickRay pickRay = DependencyManager::get()->getPickRay(_rayPickUID); + PickRay pickRay = qApp->getRayPickManager().getPickRay(_rayPickUID); if (!renderState.getStartID().isNull()) { QVariantMap startProps; startProps.insert("position", vec3toVariant(pickRay.origin)); @@ -180,7 +181,7 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { } void LaserPointer::update() { - RayPickResult prevRayPickResult = DependencyManager::get()->getPrevRayPickResult(_rayPickUID); + RayPickResult prevRayPickResult = DependencyManager::get()->getPrevRayPickResult(_rayPickUID); if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && prevRayPickResult.type != IntersectionType::NONE) { updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, prevRayPickResult.distance, prevRayPickResult.objectID, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index aaa9dad83f..d901d12cf4 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -13,10 +13,9 @@ #include #include "glm/glm.hpp" -#include "ui/overlays/Overlay.h" #include -#include "RayPickManager.h" +#include "raypick/RayPickScriptingInterface.h" class RayPickResult; @@ -52,25 +51,25 @@ public: typedef std::unordered_map RenderStateMap; typedef std::unordered_map> DefaultRenderStateMap; - LaserPointer(const QVariantMap& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, + LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); ~LaserPointer(); QUuid getRayUID() { return _rayPickUID; } void enable(); void disable(); - const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } + const RayPickResult getPrevRayPickResult() { return DependencyManager::get()->getPrevRayPickResult(_rayPickUID); } void setRenderState(const std::string& state); // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); - void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(_rayPickUID, ignoreEntities); } - void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(_rayPickUID, includeEntities); } - void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); } - void setIncludeOverlays(const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(_rayPickUID, includeOverlays); } - void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(_rayPickUID, ignoreAvatars); } - void setIncludeAvatars(const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(_rayPickUID, includeAvatars); } + void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get()->setIgnoreEntities(_rayPickUID, ignoreEntities); } + void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get()->setIncludeEntities(_rayPickUID, includeEntities); } + void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); } + void setIncludeOverlays(const QScriptValue& includeOverlays) { DependencyManager::get()->setIncludeOverlays(_rayPickUID, includeOverlays); } + void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { DependencyManager::get()->setIgnoreAvatars(_rayPickUID, ignoreAvatars); } + void setIncludeAvatars(const QScriptValue& includeAvatars) { DependencyManager::get()->setIncludeAvatars(_rayPickUID, includeAvatars); } void setLockEndUUID(QUuid objectID, const bool isOverlay) { _objectLockEnd = std::pair(objectID, isOverlay); } diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 089b9911d0..908bcc39f1 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -9,9 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "LaserPointerManager.h" -#include "RayPick.h" -QUuid LaserPointerManager::createLaserPointer(const QVariantMap& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, +QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); if (!laserPointer->getRayUID().isNull()) { diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index b981dde9fb..020b778983 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -22,7 +22,7 @@ class RayPickResult; class LaserPointerManager { public: - QUuid createLaserPointer(const QVariantMap& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, + QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); void removeLaserPointer(const QUuid uid); void enableLaserPointer(const QUuid uid); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 9b7f18d436..a976a00893 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -12,11 +12,8 @@ #include "LaserPointerScriptingInterface.h" #include -#include "RegisteredMetaTypes.h" #include "GLMHelpers.h" -#include "Application.h" - QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) { QVariantMap propertyMap = properties.toMap(); @@ -69,7 +66,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert } } - return qApp->getLaserPointerManager().createLaserPointer(propertyMap, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); + return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); } void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& renderState, const QVariant& properties) { diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 7866a5da51..8ae263b0ec 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -13,7 +13,6 @@ #include -#include "LaserPointerManager.h" #include "RegisteredMetaTypes.h" #include "DependencyManager.h" #include "Application.h" @@ -41,7 +40,7 @@ public slots: Q_INVOKABLE void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); } private: - const RenderState buildRenderState(const QVariantMap & propMap); + const RenderState buildRenderState(const QVariantMap& propMap); }; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 68c850b295..cf135ffdca 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -141,62 +141,25 @@ void RayPickManager::update() { } } -QUuid RayPickManager::createRayPick(const QVariantMap& rayProps) { - bool enabled = false; - if (rayProps["enabled"].isValid()) { - enabled = rayProps["enabled"].toBool(); - } +QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) { + QWriteLocker lock(&_addLock); + QUuid id = QUuid::createUuid(); + _rayPicksToAdd.push(std::pair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); + return id; +} - RayPickFilter filter = RayPickFilter(); - if (rayProps["filter"].isValid()) { - filter = RayPickFilter(rayProps["filter"].toUInt()); - } +QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) { + QWriteLocker lock(&_addLock); + QUuid id = QUuid::createUuid(); + _rayPicksToAdd.push(std::pair>(id, std::make_shared(filter, maxDistance, enabled))); + return id; +} - float maxDistance = 0.0f; - if (rayProps["maxDistance"].isValid()) { - maxDistance = rayProps["maxDistance"].toFloat(); - } - - if (rayProps["joint"].isValid()) { - std::string jointName = rayProps["joint"].toString().toStdString(); - - if (jointName != "Mouse") { - // x = upward, y = forward, z = lateral - glm::vec3 posOffset = Vectors::ZERO; - if (rayProps["posOffset"].isValid()) { - posOffset = vec3FromVariant(rayProps["posOffset"]); - } - - glm::vec3 dirOffset = Vectors::UP; - if (rayProps["dirOffset"].isValid()) { - dirOffset = vec3FromVariant(rayProps["dirOffset"]); - } - - QWriteLocker lock(&_addLock); - QUuid id = QUuid::createUuid(); - _rayPicksToAdd.push(std::pair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); - return id; - } else { - QWriteLocker lock(&_addLock); - QUuid id = QUuid::createUuid(); - _rayPicksToAdd.push(std::pair>(id, std::make_shared(filter, maxDistance, enabled))); - return id; - } - } else if (rayProps["position"].isValid()) { - glm::vec3 position = vec3FromVariant(rayProps["position"]); - - glm::vec3 direction = -Vectors::UP; - if (rayProps["direction"].isValid()) { - direction = vec3FromVariant(rayProps["direction"]); - } - - QWriteLocker lock(&_addLock); - QUuid id = QUuid::createUuid(); - _rayPicksToAdd.push(std::pair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); - return id; - } - - return QUuid(); +QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) { + QWriteLocker lock(&_addLock); + QUuid id = QUuid::createUuid(); + _rayPicksToAdd.push(std::pair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); + return id; } void RayPickManager::removeRayPick(const QUuid uid) { diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index e422995810..8ef2ceebe0 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -18,48 +18,32 @@ #include #include "RegisteredMetaTypes.h" -#include "DependencyManager.h" #include #include class RayPickResult; -class RayPickManager : public QObject, public Dependency { - Q_OBJECT - Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) - Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) - Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) - Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) - Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) - Q_PROPERTY(unsigned int PICK_BOUNDING_BOX READ PICK_BOUNDING_BOX CONSTANT) - Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) - Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) - Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) - SINGLETON_DEPENDENCY +class RayPickManager { public: void update(); const PickRay getPickRay(const QUuid uid); -public slots: - Q_INVOKABLE QUuid createRayPick(const QVariantMap& rayProps); - Q_INVOKABLE void removeRayPick(const QUuid uid); - Q_INVOKABLE void enableRayPick(const QUuid uid); - Q_INVOKABLE void disableRayPick(const QUuid uid); - Q_INVOKABLE const RayPickResult getPrevRayPickResult(const QUuid uid); + QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled); + QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled); + QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled); + void removeRayPick(const QUuid uid); + void enableRayPick(const QUuid uid); + void disableRayPick(const QUuid uid); + const RayPickResult getPrevRayPickResult(const QUuid uid); - Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); - Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities); - Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays); - Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays); - Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars); - Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars); + void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); + void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities); + void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays); + void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays); + void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars); + void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars); private: QHash> _rayPicks; @@ -75,22 +59,6 @@ private: // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer bool checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayPickFilter::Flags& mask); void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayPickFilter::Flags& mask, RayPickResult& res, QPair& ray, RayPickCache& cache); - - unsigned int PICK_NOTHING() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_NOTHING); } - unsigned int PICK_ENTITIES() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ENTITIES); } - unsigned int PICK_OVERLAYS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_OVERLAYS); } - unsigned int PICK_AVATARS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_AVATARS); } - unsigned int PICK_HUD() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_HUD); } - unsigned int PICK_BOUNDING_BOX() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COURSE); } - unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } - unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } - unsigned int PICK_ALL_INTERSECTIONS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } - unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } - unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } - unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } - unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } - unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } - }; #endif // hifi_RayPickManager_h \ No newline at end of file diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp new file mode 100644 index 0000000000..aa1613d696 --- /dev/null +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -0,0 +1,107 @@ +// +// RayPickScriptingInterface.cpp +// interface/src/raypick +// +// Created by Sam Gondelman 8/15/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RayPickScriptingInterface.h" + +#include +#include "GLMHelpers.h" +#include "Application.h" + +QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { + QVariantMap propMap = properties.toMap(); + + bool enabled = false; + if (propMap["enabled"].isValid()) { + enabled = propMap["enabled"].toBool(); + } + + RayPickFilter filter = RayPickFilter(); + if (propMap["filter"].isValid()) { + filter = RayPickFilter(propMap["filter"].toUInt()); + } + + float maxDistance = 0.0f; + if (propMap["maxDistance"].isValid()) { + maxDistance = propMap["maxDistance"].toFloat(); + } + + if (propMap["joint"].isValid()) { + std::string jointName = propMap["joint"].toString().toStdString(); + + if (jointName != "Mouse") { + // x = upward, y = forward, z = lateral + glm::vec3 posOffset = Vectors::ZERO; + if (propMap["posOffset"].isValid()) { + posOffset = vec3FromVariant(propMap["posOffset"]); + } + + glm::vec3 dirOffset = Vectors::UP; + if (propMap["dirOffset"].isValid()) { + dirOffset = vec3FromVariant(propMap["dirOffset"]); + } + + return qApp->getRayPickManager().createRayPick(jointName, posOffset, dirOffset, filter, maxDistance, enabled); + } else { + return qApp->getRayPickManager().createRayPick(filter, maxDistance, enabled); + } + } else if (propMap["position"].isValid()) { + glm::vec3 position = vec3FromVariant(propMap["position"]); + + glm::vec3 direction = -Vectors::UP; + if (propMap["direction"].isValid()) { + direction = vec3FromVariant(propMap["direction"]); + } + + return qApp->getRayPickManager().createRayPick(position, direction, filter, maxDistance, enabled); + } + + return QUuid(); +} + +void RayPickScriptingInterface::enableRayPick(QUuid uid) { + qApp->getRayPickManager().enableRayPick(uid); +} + +void RayPickScriptingInterface::disableRayPick(QUuid uid) { + qApp->getRayPickManager().disableRayPick(uid); +} + +void RayPickScriptingInterface::removeRayPick(QUuid uid) { + qApp->getRayPickManager().removeRayPick(uid); +} + +RayPickResult RayPickScriptingInterface::getPrevRayPickResult(QUuid uid) { + return qApp->getRayPickManager().getPrevRayPickResult(uid); +} + +void RayPickScriptingInterface::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { + qApp->getRayPickManager().setIgnoreEntities(uid, ignoreEntities); +} + +void RayPickScriptingInterface::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { + qApp->getRayPickManager().setIncludeEntities(uid, includeEntities); +} + +void RayPickScriptingInterface::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { + qApp->getRayPickManager().setIgnoreOverlays(uid, ignoreOverlays); +} + +void RayPickScriptingInterface::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { + qApp->getRayPickManager().setIncludeOverlays(uid, includeOverlays); +} + +void RayPickScriptingInterface::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { + qApp->getRayPickManager().setIgnoreAvatars(uid, ignoreAvatars); +} + +void RayPickScriptingInterface::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { + qApp->getRayPickManager().setIncludeAvatars(uid, includeAvatars); +} \ No newline at end of file diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h new file mode 100644 index 0000000000..e576b5d076 --- /dev/null +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -0,0 +1,70 @@ +// +// RayPickScriptingInterface.h +// interface/src/raypick +// +// Created by Sam Gondelman 8/15/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPickScriptingInterface_h +#define hifi_RayPickScriptingInterface_h + +#include + +#include "RegisteredMetaTypes.h" +#include "DependencyManager.h" + +#include "RayPick.h" + +class RayPickScriptingInterface : public QObject, public Dependency { + Q_OBJECT + Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) + Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) + Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) + Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) + Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) + Q_PROPERTY(unsigned int PICK_COURSE READ PICK_COURSE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) + Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) + SINGLETON_DEPENDENCY + +public slots: + Q_INVOKABLE QUuid createRayPick(const QVariant& properties); + Q_INVOKABLE void enableRayPick(QUuid uid); + Q_INVOKABLE void disableRayPick(QUuid uid); + Q_INVOKABLE void removeRayPick(QUuid uid); + Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid); + + Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities); + Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays); + Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays); + Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars); + Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars); + +private: + unsigned int PICK_NOTHING() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_NOTHING); } + unsigned int PICK_ENTITIES() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ENTITIES); } + unsigned int PICK_OVERLAYS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_OVERLAYS); } + unsigned int PICK_AVATARS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_AVATARS); } + unsigned int PICK_HUD() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_HUD); } + unsigned int PICK_COURSE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COURSE); } + unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } + unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } + unsigned int PICK_ALL_INTERSECTIONS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } + unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } + unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } + unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } + unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } + unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } +}; + +#endif // hifi_RayPickScriptingInterface_h From a641fb7a7fbe1af7a4b1b6a2cf79571203e629fe Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 15 Aug 2017 18:03:52 -0700 Subject: [PATCH 74/95] rename qvector findRayIntersection to avoid script conflicts --- interface/src/avatar/AvatarManager.cpp | 10 +++++----- interface/src/avatar/AvatarManager.h | 6 +++--- interface/src/raypick/RayPickManager.cpp | 6 +++--- interface/src/ui/overlays/Overlays.cpp | 18 +++++++++--------- interface/src/ui/overlays/Overlays.h | 8 ++++---- .../entities/src/EntityScriptingInterface.cpp | 4 ++-- .../entities/src/EntityScriptingInterface.h | 2 +- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 154cd945f1..e7a83b5abc 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -476,15 +476,15 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); - return findRayIntersection(ray, avatarsToInclude, avatarsToDiscard); + return findRayIntersectionVector(ray, avatarsToInclude, avatarsToDiscard); } -RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray, - const QVector& avatarsToInclude, - const QVector& avatarsToDiscard) { +RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard) { RayToAvatarIntersectionResult result; if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersection", + BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersectionVector", Q_RETURN_ARG(RayToAvatarIntersectionResult, result), Q_ARG(const PickRay&, ray), Q_ARG(const QVector&, avatarsToInclude), diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index c21214484b..810d419a55 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -73,9 +73,9 @@ public: Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToDiscard = QScriptValue()); - Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, - const QVector& avatarsToInclude, - const QVector& avatarsToDiscard); + RayToAvatarIntersectionResult findRayIntersectionVector(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard); // TODO: remove this HACK once we settle on optimal default sort coefficients Q_INVOKABLE float getAvatarSortCoefficient(const QString& name); diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index cf135ffdca..8b639d4a81 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -67,7 +67,7 @@ void RayPickManager::update() { bool noncollidable = rayPick->getFilter().doesPickNonCollidable(); RayPickFilter::Flags entityMask = rayPick->getFilter().getEntityFlags(); if (!checkAndCompareCachedResults(rayKey, results, res, entityMask)) { - entityRes = DependencyManager::get()->findRayIntersection(ray, true, rayPick->getIncludeEntites(), rayPick->getIgnoreEntites(), !invisible, !noncollidable); + entityRes = DependencyManager::get()->findRayIntersectionVector(ray, true, rayPick->getIncludeEntites(), rayPick->getIgnoreEntites(), !invisible, !noncollidable); fromCache = false; } @@ -84,7 +84,7 @@ void RayPickManager::update() { bool noncollidable = rayPick->getFilter().doesPickNonCollidable(); RayPickFilter::Flags overlayMask = rayPick->getFilter().getOverlayFlags(); if (!checkAndCompareCachedResults(rayKey, results, res, overlayMask)) { - overlayRes = qApp->getOverlays().findRayIntersection(ray, true, rayPick->getIncludeOverlays(), rayPick->getIgnoreOverlays(), !invisible, !noncollidable); + overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, true, rayPick->getIncludeOverlays(), rayPick->getIgnoreOverlays(), !invisible, !noncollidable); fromCache = false; } @@ -97,7 +97,7 @@ void RayPickManager::update() { if (rayPick->getFilter().doesPickAvatars()) { RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags(); if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) { - RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars()); + RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars()); cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), avatarMask, res, rayKey, results); } } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index a598788771..0f7de8bd79 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -534,15 +534,15 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, const QVector overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude); const QVector overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard); - return findRayIntersection(ray, precisionPicking, - overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly); + return findRayIntersectionVector(ray, precisionPicking, + overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly); } -RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToDiscard, - bool visibleOnly, bool collidableOnly) { +RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly, bool collidableOnly) { float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; @@ -908,21 +908,21 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRa // first priority is tablet screen overlaysToInclude << qApp->getTabletScreenID(); - rayPickResult = findRayIntersection(ray, true, overlaysToInclude, overlaysToDiscard); + rayPickResult = findRayIntersectionVector(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } // then tablet home button overlaysToInclude.clear(); overlaysToInclude << qApp->getTabletHomeButtonID(); - rayPickResult = findRayIntersection(ray, true, overlaysToInclude, overlaysToDiscard); + rayPickResult = findRayIntersectionVector(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } // then tablet frame overlaysToInclude.clear(); overlaysToInclude << OverlayID(qApp->getTabletFrameID()); - rayPickResult = findRayIntersection(ray, true, overlaysToInclude, overlaysToDiscard); + rayPickResult = findRayIntersectionVector(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 9db6375e84..1e85562485 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -217,10 +217,10 @@ public slots: bool collidableOnly = false); // Same as above but with QVectors - RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToDiscard, - bool visibleOnly = false, bool collidableOnly = false); + RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly = false, bool collidableOnly = false); /**jsdoc * Return a list of 3d overlays with bounding boxes that touch the given sphere diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 1eb9ef8462..f3e677fc29 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -682,10 +682,10 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(cons QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); - return findRayIntersection(ray, precisionPicking, entitiesToInclude, entitiesToDiscard, visibleOnly, collidableOnly); + return findRayIntersectionVector(ray, precisionPicking, entitiesToInclude, entitiesToDiscard, visibleOnly, collidableOnly); } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionVector(const PickRay& ray, bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) { PROFILE_RANGE(script_entities, __FUNCTION__); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fc5053bdd6..60c12a2f7d 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -230,7 +230,7 @@ public slots: bool visibleOnly = false, bool collidableOnly = false); /// Same as above but with QVectors - Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking, + RayToEntityIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly); From ee74f6404eb3df1a22ffe973fc326861eab4a304 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 16 Aug 2017 16:08:38 -0700 Subject: [PATCH 75/95] put back FilterLayeredItems to make samcake happy --- libraries/render/src/render/FilterTask.cpp | 15 +++++++++++++++ libraries/render/src/render/FilterTask.h | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 252006c6e7..19953f3399 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -21,6 +21,21 @@ using namespace render; +void FilterLayeredItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { + auto& scene = renderContext->_scene; + + // Clear previous values + outItems.clear(); + + // For each item, filter it into one bucket + for (auto& itemBound : inItems) { + auto& item = scene->getItem(itemBound.id); + if (item.getLayer() == _keepLayer) { + outItems.emplace_back(itemBound); + } + } +} + void SliceItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { outItems.clear(); std::static_pointer_cast(renderContext->jobConfig)->setNumItems((int)inItems.size()); diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h index 6d30f46485..1c4611ee9f 100644 --- a/libraries/render/src/render/FilterTask.h +++ b/libraries/render/src/render/FilterTask.h @@ -62,6 +62,20 @@ namespace render { } }; + // Filter the items belonging to the job's keep layer + class FilterLayeredItems { + public: + using JobModel = Job::ModelIO; + + FilterLayeredItems() {} + FilterLayeredItems(int keepLayer) : + _keepLayer(keepLayer) {} + + int _keepLayer { 0 }; + + void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); + }; + // SliceItems job config defining the slice range class SliceItemsConfig : public Job::Config { Q_OBJECT From bf35b0817903692c36d8a2835936398000691633 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 16 Aug 2017 17:27:29 -0700 Subject: [PATCH 76/95] Emoji tablet app --- .../marketplace/emoji-tablet/emojiTablet.js | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js diff --git a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js new file mode 100644 index 0000000000..c03a0225da --- /dev/null +++ b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js @@ -0,0 +1,80 @@ +/// +/// emojiTablet.js +/// A tablet app for sending emojis to other users +/// +/// Author: Elisa Lupin-Jimenez +/// Copyright High Fidelity 2017 +/// +/// Licensed under the Apache 2.0 License +/// See accompanying license file or http://apache.org/ +/// +/// All assets are under CC Attribution Non-Commerical +/// http://creativecommons.org/licenses/ +/// + +// to avoid the caching block on updating JSONs +var DEBUG = true; + +if (DEBUG) { + var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiLib.js?" + Date.now()); +} else { + var lib = Script.require("./emojiLib.js"); +} + + +(function() { + + var APP_NAME = "EMOJIS"; + var APP_URL = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiTabletUI.html?" + Date.now(); + var APP_ICON = null; + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + var button = tablet.addButton({ + //icon: APP_ICON, + text: APP_NAME + }); + + // Activates tablet UI when selected from menu + function onClicked() { + tablet.gotoWebScreen(APP_URL); + }; + button.clicked.connect(onClicked); + + // Gives position right in front of user's avatar + function getPositionToCreateEntity() { + var direction = Quat.getFront(MyAvatar.orientation); + var distance = 0.3; + var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, distance)); + position.y += 0.5; + return position; + }; + + var emojiJSON = null; + + // Handles emoji button clicks to retrieve the link to the emoji JSON from emojiLib + function onWebEventReceived(event) { + var emojiName = (JSON.parse(event)).data; + var url = lib.getEmoji(emojiName, lib.emojiLib); + if (url != null) { + emojiJSON = Script.require(url); + create3DEmoji(emojiJSON, null); + } else { + print("Unable to create emoji"); + } + }; + tablet.webEventReceived.connect(onWebEventReceived); + + function create3DEmoji(emojiJSON, userName) { + print("Creating " + emojiJSON.name + " emoji"); + emojiJSON.position = getPositionToCreateEntity(emojiJSON.personified); + var newEmoji = Entities.addEntity(emojiJSON); + }; + + // When tablet UI is closed and app is removed from menu + function cleanup() { + tablet.removeButton(button); + }; + Script.scriptEnding.connect(cleanup); + +}()); + From e03297979434f0c6e0a21476b7899abb7ca1a21a Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 16 Aug 2017 17:33:14 -0700 Subject: [PATCH 77/95] a little cleanup --- .../marketplace/emoji-tablet/emojiTablet.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js index c03a0225da..bcf336cf37 100644 --- a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js +++ b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js @@ -12,15 +12,7 @@ /// http://creativecommons.org/licenses/ /// -// to avoid the caching block on updating JSONs -var DEBUG = true; - -if (DEBUG) { - var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiLib.js?" + Date.now()); -} else { - var lib = Script.require("./emojiLib.js"); -} - +var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiLib.js?" + Date.now()); (function() { From 930f163ca160db3824f4dc7d015e07883ae6feac Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 16 Aug 2017 17:57:32 -0700 Subject: [PATCH 78/95] added app icon --- unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js index bcf336cf37..d6346ff970 100644 --- a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js +++ b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js @@ -18,11 +18,11 @@ var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_sc var APP_NAME = "EMOJIS"; var APP_URL = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiTabletUI.html?" + Date.now(); - var APP_ICON = null; + var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-a.svg"; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ - //icon: APP_ICON, + icon: APP_ICON, text: APP_NAME }); From f54e028c19bea0478b2e127474e2af7bedc6f701 Mon Sep 17 00:00:00 2001 From: EagleJumpDev Date: Wed, 16 Aug 2017 22:16:50 -0700 Subject: [PATCH 79/95] Out of memory errors detected on systems with only 6GB of main memory. Maybe 8GB should be the minimimum? --- BUILD_WIN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 3e93656d45..1a33088237 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -3,7 +3,7 @@ This is a stand-alone guide for creating your first High Fidelity build for Wind ## Building High Fidelity Note: We are now using Visual Studio 2017 and Qt 5.9.1. If you are upgrading from Visual Studio 2013 and Qt 5.6.2, do a clean uninstall of those versions before going through this guide. -Note: The prerequisites will require about 10 GB of space on your drive. +Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory. ### Step 1. Visual Studio 2017 From a9d5cb45e9345e0b56aa823697de861ab93c1aa5 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 17 Aug 2017 10:11:29 -0700 Subject: [PATCH 80/95] changed icon to white --- unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js index d6346ff970..b4d01e77cf 100644 --- a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js +++ b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js @@ -18,7 +18,7 @@ var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_sc var APP_NAME = "EMOJIS"; var APP_URL = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiTabletUI.html?" + Date.now(); - var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-a.svg"; + var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-i.svg"; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ From 4b1498f7270df125154813f9ccf41c3310d30b76 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 17 Aug 2017 10:18:29 -0700 Subject: [PATCH 81/95] moved blocksApp.js to unpublished scripts, added icon --- .../marketplace/blocks}/blocksApp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {scripts/system/marketplaces => unpublishedScripts/marketplace/blocks}/blocksApp.js (81%) diff --git a/scripts/system/marketplaces/blocksApp.js b/unpublishedScripts/marketplace/blocks/blocksApp.js similarity index 81% rename from scripts/system/marketplaces/blocksApp.js rename to unpublishedScripts/marketplace/blocks/blocksApp.js index 520b3657b9..6a48cdc101 100644 --- a/scripts/system/marketplaces/blocksApp.js +++ b/unpublishedScripts/marketplace/blocks/blocksApp.js @@ -1,7 +1,7 @@ (function() { var APP_NAME = "BLOCKS"; var APP_URL = "https://vr.google.com/objects/"; - var APP_ICON = "https://hifi-content.s3.amazonaws.com/faye/gemstoneMagicMaker/gemstoneAppIcon.svg"; + var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/blocks/blocks-i.svg"; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ From f3969b09099daf582b5629ef3af222a86a82ac1d Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 17 Aug 2017 22:28:42 +0200 Subject: [PATCH 82/95] Switch off snap behavior --- interface/resources/qml/hifi/Feed.qml | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index c1bd35f49d..201093ebad 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -237,9 +237,6 @@ Column { textSizeSmall: root.textSizeSmall; stackShadowNarrowing: root.stackShadowNarrowing; shadowHeight: root.stackedCardShadowHeight; - - hoverThunk: function () { scrollToIndex(index); } - unhoverThunk: function () { scrollToIndex(-1); } } } NumberAnimation { From 4c28b9f09a5550c722fad1304014e00623765197 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 17 Aug 2017 18:16:41 -0700 Subject: [PATCH 83/95] attempt to check version of interface --- .../scripting/WindowScriptingInterface.cpp | 4 ++++ .../src/scripting/WindowScriptingInterface.h | 1 + .../marketplace/blocks/blocksApp.js | 23 ++++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 277989439c..4cfa68b0f5 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -264,6 +264,10 @@ void WindowScriptingInterface::showAssetServer(const QString& upload) { QMetaObject::invokeMethod(qApp, "showAssetServerWidget", Qt::QueuedConnection, Q_ARG(QString, upload)); } +int WindowScriptingInterface::checkVersion() { + return QCoreApplication::applicationVersion().toInt(); +} + int WindowScriptingInterface::getInnerWidth() { return qApp->getWindow()->geometry().width(); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 28f1bafa5d..0e1f156b27 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -58,6 +58,7 @@ public slots: QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); QScriptValue browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); void showAssetServer(const QString& upload = ""); + int checkVersion(); void copyToClipboard(const QString& text); void takeSnapshot(bool notify = true, bool includeAnimated = false, float aspectRatio = 0.0f); void takeSecondaryCameraSnapshot(); diff --git a/unpublishedScripts/marketplace/blocks/blocksApp.js b/unpublishedScripts/marketplace/blocks/blocksApp.js index 6a48cdc101..f8994d5c3d 100644 --- a/unpublishedScripts/marketplace/blocks/blocksApp.js +++ b/unpublishedScripts/marketplace/blocks/blocksApp.js @@ -1,8 +1,29 @@ -(function() { +/// +/// blocksApp.js +/// A tablet app for downloading 3D assets from Google Blocks +/// +/// Author: Elisa Lupin-Jimenez +/// Copyright High Fidelity 2017 +/// +/// Licensed under the Apache 2.0 License +/// See accompanying license file or http://apache.org/ +/// +/// All assets are under CC Attribution Non-Commerical +/// http://creativecommons.org/licenses/ +/// + +(function () { var APP_NAME = "BLOCKS"; var APP_URL = "https://vr.google.com/objects/"; var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/blocks/blocks-i.svg"; + try { + print("Current Interface version: " + Script.checkVersion()); + } catch(err) { + print("Outdated Interface version does not support Blocks"); + APP_URL = null; + } + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: APP_ICON, From 4eba09214cc1ea939d84f763238a1d1c10d2ef81 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 18 Aug 2017 08:11:29 +0200 Subject: [PATCH 84/95] Delegate highlighting to delegate item. Make sure ListView will not snap highlighted item --- interface/resources/qml/hifi/Card.qml | 9 +++++++++ interface/resources/qml/hifi/Feed.qml | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index fd76c03e45..678245910b 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -46,6 +46,8 @@ Item { property int stackShadowNarrowing: 5; property string defaultThumbnail: Qt.resolvedUrl("../../images/default-domain.gif"); property int shadowHeight: 10; + property bool hovered: false + HifiConstants { id: hifi } function pastTime(timestamp) { // Answer a descriptive string @@ -231,6 +233,13 @@ Item { // to that which is being hovered over. property var hoverThunk: function () { }; property var unhoverThunk: function () { }; + Rectangle { + anchors.fill: parent; + visible: root.hovered + color: "transparent"; + border.width: 4; border.color: hifiStyleConstants.colors.primaryHighlight; + z: 1; + } MouseArea { anchors.fill: parent; acceptedButtons: Qt.LeftButton; diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index 201093ebad..960b62c169 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -206,9 +206,9 @@ Column { id: scroll; model: suggestions; orientation: ListView.Horizontal; + highlightFollowsCurrentItem: false highlightMoveDuration: -1; highlightMoveVelocity: -1; - highlight: Rectangle { color: "transparent"; border.width: 4; border.color: hifiStyleConstants.colors.primaryHighlight; z: 1; } currentIndex: -1; spacing: 12; @@ -237,6 +237,8 @@ Column { textSizeSmall: root.textSizeSmall; stackShadowNarrowing: root.stackShadowNarrowing; shadowHeight: root.stackedCardShadowHeight; + hoverThunk: function () { hovered = true } + unhoverThunk: function () { hovered = false } } } NumberAnimation { From 3d401129fbb005de82a064f88510149e6f05485f Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 18 Aug 2017 10:03:00 -0700 Subject: [PATCH 85/95] checkpoint --- interface/resources/qml/controls/WebView.qml | 2 +- .../resources/qml/hifi/commerce/Checkout.qml | 19 +-- .../resources/qml/hifi/commerce/Inventory.qml | 12 +- interface/src/commerce/Ledger.cpp | 108 +++++++++++------- interface/src/commerce/Ledger.h | 34 ++++-- interface/src/commerce/QmlCommerce.cpp | 7 +- interface/src/commerce/QmlCommerce.h | 7 +- interface/src/commerce/Wallet.cpp | 13 ++- .../HFTabletWebEngineRequestInterceptor.cpp | 2 +- scripts/system/html/js/marketplacesInject.js | 6 +- 10 files changed, 127 insertions(+), 83 deletions(-) diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 38136c7eec..23782983ce 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -73,7 +73,7 @@ Item { console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); }); - root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; + root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface WithHFC)"; } onFeaturePermissionRequested: { diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml index b9d15b61e4..55bd6cb4c6 100644 --- a/interface/resources/qml/hifi/commerce/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -35,8 +35,8 @@ Rectangle { Hifi.QmlCommerce { id: commerce; onBuyResult: { - if (failureMessage.length) { - buyButton.text = "Buy Failed"; + if (result.status !== 'success') { + buyButton.text = result.message; buyButton.enabled = false; } else { if (urlHandler.canHandleUrl(itemHref)) { @@ -46,20 +46,21 @@ Rectangle { } } onBalanceResult: { - if (failureMessage.length) { - console.log("Failed to get balance", failureMessage); + if (result.status !== 'success') { + console.log("Failed to get balance", result.message); } else { balanceReceived = true; - hfcBalanceText.text = balance; - balanceAfterPurchase = balance - parseInt(itemPriceText.text, 10); + hfcBalanceText.text = result.data.balance; + balanceAfterPurchase = result.data.balance - parseInt(itemPriceText.text, 10); } } onInventoryResult: { - if (failureMessage.length) { - console.log("Failed to get inventory", failureMessage); + if (result.status !== 'success') { + console.log("Failed to get inventory", result.message); } else { inventoryReceived = true; - if (inventoryContains(inventory.assets, itemId)) { + console.log('inventory fixme', JSON.stringify(result)); + if (inventoryContains(result.data.assets, itemId)) { alreadyOwned = true; } else { alreadyOwned = false; diff --git a/interface/resources/qml/hifi/commerce/Inventory.qml b/interface/resources/qml/hifi/commerce/Inventory.qml index d7ffae7c3c..8f22e7de0f 100644 --- a/interface/resources/qml/hifi/commerce/Inventory.qml +++ b/interface/resources/qml/hifi/commerce/Inventory.qml @@ -30,17 +30,17 @@ Rectangle { Hifi.QmlCommerce { id: commerce; onBalanceResult: { - if (failureMessage.length) { - console.log("Failed to get balance", failureMessage); + if (result.status !== 'success') { + console.log("Failed to get balance", result.message); } else { - hfcBalanceText.text = balance; + hfcBalanceText.text = result.data.balance; } } onInventoryResult: { - if (failureMessage.length) { - console.log("Failed to get inventory", failureMessage); + if (result.status !== 'success') { + console.log("Failed to get inventory", result.message); } else { - inventoryContentsList.model = inventory.assets; + inventoryContentsList.model = result.data.assets; } } onSecurityImageResult: { diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 8d7d47aca0..55ee0e16e9 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -10,72 +10,100 @@ // #include +#include #include #include "AccountManager.h" #include "Wallet.h" #include "Ledger.h" #include "CommerceLogging.h" +// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}} +// balance answers {status: 'success', data: {balance: integer}} +// buy and receive_at answer {status: 'success'} + +QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply& reply) { + QByteArray response = reply.readAll(); + QJsonObject data = QJsonDocument::fromJson(response).object(); + qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact); + return data; +} +// Non-200 responses are not json: +QJsonObject Ledger::failResponse(const QString& label, QNetworkReply& reply) { + QString response = reply.readAll(); + qWarning(commerce) << "FAILED" << label << response; + QJsonObject result + { + { "status", "fail" }, + { "message", response } + }; + return result; +} +#define ApiHandler(NAME) void Ledger::NAME##Success(QNetworkReply& reply) { emit NAME##Result(apiResponse(#NAME, reply)); } +#define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply& reply) { emit NAME##Result(failResponse(#NAME, reply)); } +#define Handler(NAME) ApiHandler(NAME) FailHandler(NAME) +Handler(buy) +Handler(receiveAt) +Handler(balance) +Handler(inventory) + +void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) { + auto accountManager = DependencyManager::get(); + const QString URL = "/api/v1/commerce/"; + JSONCallbackParameters callbackParams(this, success, this, fail); + qCInfo(commerce) << "Sending" << endpoint << QJsonDocument(request).toJson(QJsonDocument::Compact); + accountManager->sendRequest(URL + endpoint, + AccountManagerAuth::Required, + method, + callbackParams, + QJsonDocument(request).toJson()); +} + +void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail) { + auto wallet = DependencyManager::get(); + QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key); + QJsonObject request; + request[propertyName] = QString(text); + request["signature"] = signature; + send(endpoint, success, fail, QNetworkAccessManager::PutOperation, request); +} + +void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) { + auto wallet = DependencyManager::get(); + QJsonObject request; + request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); + send(endpoint, success, fail, QNetworkAccessManager::PostOperation, request); +} + void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const QString& buyerUsername) { QJsonObject transaction; transaction["hfc_key"] = hfc_key; - transaction["hfc"] = cost; + transaction["cost"] = cost; transaction["asset_id"] = asset_id; transaction["inventory_key"] = inventory_key; transaction["inventory_buyer_username"] = buyerUsername; QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - - auto wallet = DependencyManager::get(); - QString signature = wallet->signWithKey(transactionString, hfc_key); - QJsonObject request; - request["transaction"] = QString(transactionString); - request["signature"] = signature; - - qCInfo(commerce) << "Transaction:" << QJsonDocument(request).toJson(QJsonDocument::Compact); - // FIXME: talk to server instead - if (_inventory.contains(asset_id)) { - // This is here more for testing than as a definition of semantics. - // When we have popcerts, you will certainly be able to buy a new instance of an item that you already own a different instance of. - // I'm not sure what the server should do for now in this project's MVP. - return emit buyResult("Already owned."); - } - if (initializedBalance() < cost) { - return emit buyResult("Insufficient funds."); - } - _balance -= cost; - QJsonObject inventoryAdditionObject; - inventoryAdditionObject["id"] = asset_id; - inventoryAdditionObject["title"] = "Test Title"; - inventoryAdditionObject["preview"] = "https://www.aspca.org/sites/default/files/cat-care_cat-nutrition-tips_overweight_body4_left.jpg"; - _inventory.push_back(inventoryAdditionObject); - emit buyResult(""); + signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure"); } -bool Ledger::receiveAt(const QString& hfc_key) { +bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { qCWarning(commerce) << "Cannot set receiveAt when not logged in."; - emit receiveAtResult("Not logged in"); + QJsonObject result{ { "status", "fail" }, { "message", "Not logged in" } }; + emit receiveAtResult(result); return false; // We know right away that we will fail, so tell the caller. } - auto username = accountManager->getAccountInfo().getUsername(); - qCInfo(commerce) << "Setting default receiving key for" << username; - emit receiveAtResult(""); // FIXME: talk to server instead. + + signedSend("public_key", hfc_key.toUtf8(), old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } void Ledger::balance(const QStringList& keys) { - // FIXME: talk to server instead - qCInfo(commerce) << "Balance:" << initializedBalance(); - emit balanceResult(_balance, ""); + keysQuery("balance", "balanceSuccess", "balanceFailure"); } void Ledger::inventory(const QStringList& keys) { - // FIXME: talk to server instead - QJsonObject inventoryObject; - inventoryObject.insert("success", true); - inventoryObject.insert("assets", _inventory); - qCInfo(commerce) << "Inventory:" << inventoryObject; - emit inventoryResult(inventoryObject, ""); + keysQuery("inventory", "inventorySuccess", "inventoryFailure"); } + diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 74ed8c1ab3..e43b8453b9 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -14,9 +14,10 @@ #ifndef hifi_Ledger_h #define hifi_Ledger_h +#include #include -#include -#include +#include + class Ledger : public QObject, public Dependency { Q_OBJECT @@ -24,21 +25,32 @@ class Ledger : public QObject, public Dependency { public: void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const QString& buyerUsername = ""); - bool receiveAt(const QString& hfc_key); + bool receiveAt(const QString& hfc_key, const QString& old_key); void balance(const QStringList& keys); void inventory(const QStringList& keys); signals: - void buyResult(const QString& failureReason); - void receiveAtResult(const QString& failureReason); - void balanceResult(int balance, const QString& failureReason); - void inventoryResult(QJsonObject inventory, const QString& failureReason); + void buyResult(QJsonObject result); + void receiveAtResult(QJsonObject result); + void balanceResult(QJsonObject result); + void inventoryResult(QJsonObject result); + +public slots: + void buySuccess(QNetworkReply& reply); + void buyFailure(QNetworkReply& reply); + void receiveAtSuccess(QNetworkReply& reply); + void receiveAtFailure(QNetworkReply& reply); + void balanceSuccess(QNetworkReply& reply); + void balanceFailure(QNetworkReply& reply); + void inventorySuccess(QNetworkReply& reply); + void inventoryFailure(QNetworkReply& reply); private: - // These in-memory caches is temporary, until we start sending things to the server. - int _balance{ -1 }; - QJsonArray _inventory{}; - int initializedBalance() { if (_balance < 0) _balance = 100; return _balance; } + QJsonObject apiResponse(const QString& label, QNetworkReply& reply); + QJsonObject failResponse(const QString& label, QNetworkReply& reply); + void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request); + void keysQuery(const QString& endpoint, const QString& success, const QString& fail); + void signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail); }; #endif // hifi_Ledger_h diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 573740727f..abd0e52f78 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -31,14 +31,15 @@ void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUser auto wallet = DependencyManager::get(); QStringList keys = wallet->listPublicKeys(); if (keys.count() == 0) { - return emit buyResult("Uninitialized Wallet."); + QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; + return emit buyResult(result); } QString key = keys[0]; // For now, we receive at the same key that pays for it. ledger->buy(key, cost, assetId, key, buyerUsername); // FIXME: until we start talking to server, report post-transaction balance and inventory so we can see log for testing. - balance(); - inventory(); + /*balance(); + inventory();*/ } void QmlCommerce::balance() { diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 5b702bfeff..bb067146ba 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -15,6 +15,7 @@ #ifndef hifi_QmlCommerce_h #define hifi_QmlCommerce_h +#include #include class QmlCommerce : public OffscreenQmlDialog { @@ -25,11 +26,11 @@ public: QmlCommerce(QQuickItem* parent = nullptr); signals: - void buyResult(const QString& failureMessage); + void buyResult(QJsonObject result); // Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and // because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain). - void balanceResult(int balance, const QString& failureMessage); - void inventoryResult(QJsonObject inventory, const QString& failureMessage); + void balanceResult(QJsonObject result); + void inventoryResult(QJsonObject result); void securityImageResult(uint imageID); protected: diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index f47b174d88..05ccea3a59 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -205,7 +205,7 @@ bool Wallet::createIfNeeded() { qCDebug(commerce) << "read private key"; RSA_free(key); // K -- add the public key since we have a legit private key associated with it - _publicKeys.push_back(QUrl::toPercentEncoding(publicKey.toBase64())); + _publicKeys.push_back(publicKey.toBase64()); return false; } } @@ -216,16 +216,17 @@ bool Wallet::createIfNeeded() { bool Wallet::generateKeyPair() { qCInfo(commerce) << "Generating keypair."; auto keyPair = generateRSAKeypair(); - - _publicKeys.push_back(QUrl::toPercentEncoding(keyPair.first->toBase64())); - qCDebug(commerce) << "public key:" << _publicKeys.last(); + QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last(); + QString key = keyPair.first->toBase64(); + _publicKeys.push_back(key); + qCDebug(commerce) << "public key:" << key; // It's arguable whether we want to change the receiveAt every time, but: // 1. It's certainly needed the first time, when createIfNeeded answers true. // 2. It is maximally private, and we can step back from that later if desired. // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. auto ledger = DependencyManager::get(); - return ledger->receiveAt(_publicKeys.last()); + return ledger->receiveAt(key, oldKey); } QStringList Wallet::listPublicKeys() { qCInfo(commerce) << "Enumerating public keys."; @@ -260,7 +261,7 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) { RSA_free(rsaPrivateKey); if (encryptReturn != -1) { - return QUrl::toPercentEncoding(signature.toBase64()); + return signature.toBase64(); } } return QString(); diff --git a/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp b/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp index 6ee8589615..405a402a8b 100644 --- a/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp +++ b/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp @@ -36,7 +36,7 @@ void HFTabletWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestI } static const QString USER_AGENT = "User-Agent"; - QString tokenString = "Chrome/48.0 (HighFidelityInterface)"; + QString tokenString = "Chrome/48.0 (HighFidelityInterface WithHFC)"; info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit()); } else { static const QString USER_AGENT = "User-Agent"; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 80c8f8a0e4..41b57060cc 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -114,7 +114,7 @@ itemId: id, itemName: name, itemAuthor: author, - itemPrice: Math.round(Math.random() * 50), + itemPrice: price ? parseInt(price, 10) : Math.round(Math.random() * 50), itemHref: href })); } @@ -129,7 +129,7 @@ buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'), $(this).closest('.grid-item').find('.item-title').text(), $(this).closest('.grid-item').find('.creator').find('.value').text(), - 10, + $(this).closest('.grid-item').find('.item-cost').text(), $(this).attr('data-href')); }); } @@ -165,7 +165,7 @@ buyButtonClicked(window.location.pathname.split("/")[3], $('#top-center').find('h1').text(), $('#creator').find('.value').text(), - 10, + $('.item-cost').text(), href); }); addInventoryButton(); From c9f4958925979aea07c2df9e68a1eea2dc02ac4e Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 18 Aug 2017 10:39:40 -0700 Subject: [PATCH 86/95] handControllerGrab fix, maybe, hopefully --- scripts/system/controllers/handControllerGrab.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 44f79a5570..9318873f64 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -352,7 +352,7 @@ function projectOntoXYPlane(worldPos, position, rotation, dimensions, registrati function projectOntoEntityXYPlane(entityID, worldPos) { var props = entityPropertiesCache.getProps(entityID); - if (props) { + if (props && props.position && props.rotation && props.dimensions && props.registrationPoint) { return projectOntoXYPlane(worldPos, props.position, props.rotation, props.dimensions, props.registrationPoint); } } @@ -368,16 +368,20 @@ function projectOntoOverlayXYPlane(overlayID, worldPos) { var resolution = Overlays.getProperty(overlayID, "resolution"); resolution.z = 1; // Circumvent divide-by-zero. var scale = Overlays.getProperty(overlayID, "dimensions"); - scale.z = 0.01; // overlay dimensions are 2D, not 3D. - dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale); + if (scale) { + scale.z = 0.01; // overlay dimensions are 2D, not 3D. + dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale); + } } else { dimensions = Overlays.getProperty(overlayID, "dimensions"); - if (dimensions.z) { + if (dimensions && dimensions.z) { dimensions.z = 0.01; // overlay dimensions are 2D, not 3D. } } - return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); + if (position && rotation && dimensions) { + return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); + } } function handLaserIntersectItem(position, rotation, start) { From 65f876acf3274816f8b9baf46996752fae9a9d16 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Fri, 18 Aug 2017 10:49:40 -0700 Subject: [PATCH 87/95] enabled version check --- interface/src/scripting/WindowScriptingInterface.cpp | 4 ++-- interface/src/scripting/WindowScriptingInterface.h | 2 +- unpublishedScripts/marketplace/blocks/blocksApp.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 4cfa68b0f5..f63c128cf5 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -264,8 +264,8 @@ void WindowScriptingInterface::showAssetServer(const QString& upload) { QMetaObject::invokeMethod(qApp, "showAssetServerWidget", Qt::QueuedConnection, Q_ARG(QString, upload)); } -int WindowScriptingInterface::checkVersion() { - return QCoreApplication::applicationVersion().toInt(); +QString WindowScriptingInterface::checkVersion() { + return QCoreApplication::applicationVersion(); } int WindowScriptingInterface::getInnerWidth() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 0e1f156b27..4b5e2e81fc 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -58,7 +58,7 @@ public slots: QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); QScriptValue browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); void showAssetServer(const QString& upload = ""); - int checkVersion(); + QString checkVersion(); void copyToClipboard(const QString& text); void takeSnapshot(bool notify = true, bool includeAnimated = false, float aspectRatio = 0.0f); void takeSecondaryCameraSnapshot(); diff --git a/unpublishedScripts/marketplace/blocks/blocksApp.js b/unpublishedScripts/marketplace/blocks/blocksApp.js index f8994d5c3d..2c20e13005 100644 --- a/unpublishedScripts/marketplace/blocks/blocksApp.js +++ b/unpublishedScripts/marketplace/blocks/blocksApp.js @@ -18,10 +18,10 @@ var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/blocks/blocks-i.svg"; try { - print("Current Interface version: " + Script.checkVersion()); + print("Current Interface version: " + Window.checkVersion()); } catch(err) { print("Outdated Interface version does not support Blocks"); - APP_URL = null; + APP_URL = "https://hifi-content.s3.amazonaws.com/elisalj/blocks/updateToBlocks.html"; } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); From d29d4b5016176a394eca5dd33e7dba537e4f1239 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 18 Aug 2017 21:44:44 +0200 Subject: [PATCH 88/95] Adopt clonable settings to new styling --- scripts/system/html/entityProperties.html | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 24a8b2fee0..f94d339f84 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -133,20 +133,20 @@
    -
    - - @@ -681,4 +681,4 @@ - \ No newline at end of file + From bd37679b657f94e1a5d626110c7df7fec8f16e25 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 18 Aug 2017 14:03:40 -0700 Subject: [PATCH 89/95] working --- interface/resources/qml/TabletBrowser.qml | 2 +- .../qml/controls/TabletWebScreen.qml | 2 +- .../resources/qml/controls/TabletWebView.qml | 4 +- interface/resources/qml/controls/WebView.qml | 1 - interface/resources/qml/hifi/WebBrowser.qml | 2 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 2 - .../src/ui/types/HFTabletWebEngineProfile.cpp | 27 ----------- .../HFTabletWebEngineRequestInterceptor.cpp | 46 ------------------- .../ui/src/ui/types/HFWebEngineProfile.cpp | 2 - libraries/ui/src/ui/types/RequestFilters.cpp | 15 +++++- 10 files changed, 18 insertions(+), 85 deletions(-) delete mode 100644 libraries/ui/src/ui/types/HFTabletWebEngineProfile.cpp delete mode 100644 libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index c3d879c513..0b06a6e2a1 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -39,7 +39,7 @@ Item { width: parent.width height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height - profile: HFTabletWebEngineProfile; + profile: HFWebEngineProfile; property string userScriptUrl: "" diff --git a/interface/resources/qml/controls/TabletWebScreen.qml b/interface/resources/qml/controls/TabletWebScreen.qml index 68f8226e21..1de31aba41 100644 --- a/interface/resources/qml/controls/TabletWebScreen.qml +++ b/interface/resources/qml/controls/TabletWebScreen.qml @@ -31,7 +31,7 @@ Item { width: parent.width height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height - profile: HFTabletWebEngineProfile; + profile: HFWebEngineProfile; property string userScriptUrl: "" diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 0a5a68717e..dd40b55b84 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -142,7 +142,7 @@ Item { width: parent.width height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - web.headerHeight : parent.height - web.headerHeight anchors.top: buttons.bottom - profile: HFTabletWebEngineProfile; + profile: HFWebEngineProfile; property string userScriptUrl: "" @@ -182,8 +182,6 @@ Item { webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); }); - - webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; } onFeaturePermissionRequested: { diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 23782983ce..3f2ac6363b 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -73,7 +73,6 @@ Item { console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); }); - root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface WithHFC)"; } onFeaturePermissionRequested: { diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index f639586668..af54c86bf4 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -147,7 +147,7 @@ Rectangle { width: parent.width; height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight - profile: HFTabletWebEngineProfile; + profile: HFWebEngineProfile; property string userScriptUrl: "" diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 2012ebbe30..47b526c925 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -43,7 +43,6 @@ #include "types/FileTypeProfile.h" #include "types/HFWebEngineProfile.h" -#include "types/HFTabletWebEngineProfile.h" #include "types/SoundEffect.h" #include "Logging.h" @@ -328,7 +327,6 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { } rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext)); rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext)); - rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext)); rootContext->setContextProperty("Paths", DependencyManager::get().data()); } diff --git a/libraries/ui/src/ui/types/HFTabletWebEngineProfile.cpp b/libraries/ui/src/ui/types/HFTabletWebEngineProfile.cpp deleted file mode 100644 index a3e3906497..0000000000 --- a/libraries/ui/src/ui/types/HFTabletWebEngineProfile.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// -// HFTabletWebEngineProfile.h -// interface/src/networking -// -// Created by Dante Ruiz on 2017-03-31. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "HFTabletWebEngineProfile.h" -#include "HFTabletWebEngineRequestInterceptor.h" - -static const QString QML_WEB_ENGINE_NAME = "qmlTabletWebEngine"; - -HFTabletWebEngineProfile::HFTabletWebEngineProfile(QObject* parent) : QQuickWebEngineProfile(parent) { - - static const QString WEB_ENGINE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; - - setHttpUserAgent(WEB_ENGINE_USER_AGENT); - setStorageName(QML_WEB_ENGINE_NAME); - - auto requestInterceptor = new HFTabletWebEngineRequestInterceptor(this); - setRequestInterceptor(requestInterceptor); -} - diff --git a/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp b/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp deleted file mode 100644 index 405a402a8b..0000000000 --- a/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// HFTabletWebEngineRequestInterceptor.cpp -// interface/src/networking -// -// Created by Dante Ruiz on 2017-3-31. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "HFTabletWebEngineRequestInterceptor.h" -#include -#include "AccountManager.h" - -bool isTabletAuthableHighFidelityURL(const QUrl& url) { - static const QStringList HF_HOSTS = { - "highfidelity.com", "highfidelity.io", - "metaverse.highfidelity.com", "metaverse.highfidelity.io" - }; - - return url.scheme() == "https" && HF_HOSTS.contains(url.host()); -} - -void HFTabletWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { - // check if this is a request to a highfidelity URL - if (isTabletAuthableHighFidelityURL(info.requestUrl())) { - // if we have an access token, add it to the right HTTP header for authorization - auto accountManager = DependencyManager::get(); - - if (accountManager->hasValidAccessToken()) { - static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization"; - - QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token; - info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit()); - } - - static const QString USER_AGENT = "User-Agent"; - QString tokenString = "Chrome/48.0 (HighFidelityInterface WithHFC)"; - info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit()); - } else { - static const QString USER_AGENT = "User-Agent"; - QString tokenString = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; - info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit()); - } -} diff --git a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp index a69d4d653b..685af45dad 100644 --- a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp +++ b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp @@ -18,8 +18,6 @@ static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine"; HFWebEngineProfile::HFWebEngineProfile(QObject* parent) : QQuickWebEngineProfile(parent) { - static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)"; - setHttpUserAgent(WEB_ENGINE_USER_AGENT); setStorageName(QML_WEB_ENGINE_STORAGE_NAME); // we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user diff --git a/libraries/ui/src/ui/types/RequestFilters.cpp b/libraries/ui/src/ui/types/RequestFilters.cpp index 3e72b8a8bd..6ef3effa4c 100644 --- a/libraries/ui/src/ui/types/RequestFilters.cpp +++ b/libraries/ui/src/ui/types/RequestFilters.cpp @@ -13,6 +13,7 @@ #include "NetworkingConstants.h" #include +#include #include "AccountManager.h" @@ -42,7 +43,8 @@ namespace { void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) { // check if this is a request to a highfidelity URL - if (isAuthableHighFidelityURL(info.requestUrl())) { + bool isAuthable = isAuthableHighFidelityURL(info.requestUrl()); + if (isAuthable) { // if we have an access token, add it to the right HTTP header for authorization auto accountManager = DependencyManager::get(); @@ -53,6 +55,17 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit()); } } + static const QString USER_AGENT = "User-Agent"; + const QString tokenStringMobile{ "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36" }; + const QString tokenStringMetaverse{ "Chrome/48.0 (HighFidelityInterface)" }; + + // During the period in which we have HFC commerce in the system, but not applied everywhere: + const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" }; + static Setting::Handle _settingSwitch{ "inspectionMode", false }; + bool isMoney = _settingSwitch.get(); + + const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse); + info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit()); } void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) { From 29b717e22d98d2f494b50dbc5a899a3d49888424 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 18 Aug 2017 14:08:04 -0700 Subject: [PATCH 90/95] remove dead code --- interface/src/commerce/QmlCommerce.cpp | 5 +---- interface/src/commerce/QmlCommerce.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index abd0e52f78..b3d6a5e67a 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -1,5 +1,5 @@ // -// Commerce.cpp +// QmlCommerce.cpp // interface/src/commerce // // Created by Howard Stearns on 8/4/17. @@ -37,9 +37,6 @@ void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUser QString key = keys[0]; // For now, we receive at the same key that pays for it. ledger->buy(key, cost, assetId, key, buyerUsername); - // FIXME: until we start talking to server, report post-transaction balance and inventory so we can see log for testing. - /*balance(); - inventory();*/ } void QmlCommerce::balance() { diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index bb067146ba..4112ab7177 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -1,5 +1,5 @@ // -// Commerce.h +// QmlCommerce.h // interface/src/commerce // // Guard for safe use of Commerce (Wallet, Ledger) by authorized QML. From 5f162c03520428b5ac829be5a06ae9748288b387 Mon Sep 17 00:00:00 2001 From: Midnight Date: Fri, 18 Aug 2017 15:10:58 -0700 Subject: [PATCH 91/95] Change emitShouldTrail to emitterShouldTrail. --- scripts/system/particle_explorer/particleExplorer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/particle_explorer/particleExplorer.js b/scripts/system/particle_explorer/particleExplorer.js index ca6a873b73..057bd1dd85 100644 --- a/scripts/system/particle_explorer/particleExplorer.js +++ b/scripts/system/particle_explorer/particleExplorer.js @@ -178,8 +178,8 @@ type: "Row" }, { - id: "emitShouldTrail", - name: "Emit Should Trail", + id: "emitterShouldTrail", + name: "Emitter Should Trail", type: "Boolean" }, { From 099723fe4dadb15497abf2a6b25e10afa8942320 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 20 Aug 2017 13:49:26 -0700 Subject: [PATCH 92/95] Use RAII to avoid deletion of extended argv while in use --- interface/src/main.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 084e540ff4..503daa177d 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -216,17 +216,12 @@ int main(int argc, const char* argv[]) { SandboxUtils::runLocalSandbox(serverContentPath, true, noUpdater); } - // to enable WebGL rendering - char* additionalCommandLineArg = (char*)"--ignore-gpu-blacklist"; - int newArgc = argc + 1; - char** newArgv = new char*[newArgc]; - for (int i = 0; i < argc; ++i) { - newArgv[i] = (char*)argv[i]; - } - newArgv[argc] = additionalCommandLineArg; + // Extend argv to enable WebGL rendering + std::vector argvExtended(&argv[0], &argv[argc]); + argvExtended.push_back("--ignore-gpu-blacklist"); + int argcExtended = (int)argvExtended.size(); - Application app(newArgc, const_cast(newArgv), startupTime, runningMarkerExisted); - delete[] newArgv; + Application app(argcExtended, const_cast(argvExtended.data()), startupTime, runningMarkerExisted); // If we failed the OpenGLVersion check, log it. if (override) { From 1eb7fb5b3d0b6e32f86b59aca0508d1decf6e702 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Aug 2017 17:15:44 -0700 Subject: [PATCH 93/95] always write rank ID to variant when present --- libraries/networking/src/NodePermissions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index cc5df515aa..e94c43b6fb 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -53,8 +53,12 @@ QVariant NodePermissions::toVariant(QHash groupRanks) { values["permissions_id"] = _id; if (_groupIDSet) { values["group_id"] = _groupID; - if (groupRanks.contains(_rankID)) { + + if (!_rankID.isNull()) { values["rank_id"] = _rankID; + } + + if (groupRanks.contains(_rankID)) { values["rank_name"] = groupRanks[_rankID].name; values["rank_order"] = groupRanks[_rankID].order; } From b7a048c6eae264e8d42436357c2cb18e2f96cd54 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 18 Aug 2017 21:44:44 +0200 Subject: [PATCH 94/95] Adopt clonable settings to new styling --- scripts/system/html/entityProperties.html | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 24a8b2fee0..f94d339f84 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -133,20 +133,20 @@
    -
    - - @@ -681,4 +681,4 @@ - \ No newline at end of file + From 9dfc74de574c6eec004a60f79434a22fb9bc0112 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Aug 2017 17:15:44 -0700 Subject: [PATCH 95/95] always write rank ID to variant when present --- libraries/networking/src/NodePermissions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index cc5df515aa..e94c43b6fb 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -53,8 +53,12 @@ QVariant NodePermissions::toVariant(QHash groupRanks) { values["permissions_id"] = _id; if (_groupIDSet) { values["group_id"] = _groupID; - if (groupRanks.contains(_rankID)) { + + if (!_rankID.isNull()) { values["rank_id"] = _rankID; + } + + if (groupRanks.contains(_rankID)) { values["rank_name"] = groupRanks[_rankID].name; values["rank_order"] = groupRanks[_rankID].order; }