diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 23fec03ac2..649ea49153 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -49,9 +49,14 @@ ScrollingWindow { Component.onCompleted: { ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); + assetMappingsModel.autoRefreshEnabled = true; reload(); } + + Component.onDestruction: { + assetMappingsModel.autoRefreshEnabled = false; + } function doDeleteFile(path) { console.log("Deleting " + path); @@ -146,7 +151,6 @@ ScrollingWindow { function reload() { Assets.mappingModel.refresh(); - treeView.selection.clear(); } function handleGetMappingsError(errorString) { @@ -502,16 +506,6 @@ ScrollingWindow { onClicked: root.deleteFile() enabled: treeView.selection.hasSelection } - - HifiControls.GlyphButton { - - glyph: hifi.glyphs.reload - color: hifi.buttons.black - colorScheme: root.colorScheme - width: hifi.dimensions.controlLineHeight - - onClicked: root.reload() - } } } @@ -751,7 +745,7 @@ ScrollingWindow { var path = assetProxyModel.data(index, 0x100); mappings.push(path); } - print("Setting baking enabled:" + mappings + checked); + print("Setting baking enabled:" + mappings + " " + checked); Assets.setBakingEnabled(mappings, checked, function() { reload(); }); diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 61f5a382ad..3f1fcf6bda 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -49,9 +49,15 @@ Rectangle { isHMD = HMD.active; ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); + assetMappingsModel.autoRefreshEnabled = true; + reload(); } + Component.onDestruction: { + assetMappingsModel.autoRefreshEnabled = false; + } + function doDeleteFile(path) { console.log("Deleting " + path); @@ -145,7 +151,6 @@ Rectangle { function reload() { Assets.mappingModel.refresh(); - treeView.selection.clear(); } function handleGetMappingsError(errorString) { @@ -502,16 +507,6 @@ Rectangle { onClicked: root.deleteFile() enabled: treeView.selection.hasSelection } - - HifiControls.GlyphButton { - - glyph: hifi.glyphs.reload - color: hifi.buttons.black - colorScheme: root.colorScheme - width: hifi.dimensions.controlLineHeight - - onClicked: root.reload() - } } } @@ -748,7 +743,7 @@ Rectangle { var path = assetProxyModel.data(index, 0x100); mappings.push(path); } - print("Setting baking enabled:" + mappings + checked); + print("Setting baking enabled:" + mappings + " " + checked); Assets.setBakingEnabled(mappings, checked, function() { reload(); }); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f7116a60db..e508c972c6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2196,6 +2196,14 @@ float MyAvatar::getDomainMaxScale() { return _domainMaximumScale; } +void MyAvatar::setGravity(float gravity) { + _characterController.setGravity(gravity); +} + +float MyAvatar::getGravity() { + return _characterController.getGravity(); +} + void MyAvatar::increaseSize() { // make sure we're starting from an allowable scale clampTargetScaleToDomainLimits(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c9d073cfd9..9620d61a49 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -152,7 +152,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float userHeight READ getUserHeight WRITE setUserHeight) Q_PROPERTY(float userEyeHeight READ getUserEyeHeight) - + const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; @@ -551,6 +551,9 @@ public slots: float getDomainMinScale(); float getDomainMaxScale(); + void setGravity(float gravity); + float getGravity(); + void goToLocation(const glm::vec3& newPosition, bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(), bool shouldFaceLocation = false); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index b696afa8e5..55ddd01123 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -92,8 +92,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 = qApp->getRayPickManager().getPickRay(_rayPickUID); +void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) { if (!renderState.getStartID().isNull()) { QVariantMap startProps; startProps.insert("position", vec3toVariant(pickRay.origin)); @@ -185,12 +184,14 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { void LaserPointer::update() { 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); + if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && + (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { + float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; + updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); - updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), true); + updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true); } 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 23f023cf7a..5467a8233e 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -65,6 +65,7 @@ public: void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); void setPrecisionPicking(const bool precisionPicking) { DependencyManager::get()->setPrecisionPicking(_rayPickUID, precisionPicking); } + void setLaserLength(const float laserLength) { _laserLength = laserLength; } 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); } @@ -78,6 +79,7 @@ public: private: bool _renderingEnabled; + float _laserLength { 0.0f }; std::string _currentRenderState { "" }; RenderStateMap _renderStates; DefaultRenderStateMap _defaultRenderStates; @@ -89,7 +91,7 @@ private: 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 updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState); void disableRenderState(const RenderState& renderState); }; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 1fd0fe9e88..b19ecc14f0 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -14,17 +14,19 @@ QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const La 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); + QWriteLocker containsLock(&_containsLock); QUuid id = QUuid::createUuid(); - _laserPointersToAdd.push(std::pair>(id, laserPointer)); + _laserPointers[id] = laserPointer; + _laserPointerLocks[id] = std::make_shared(); return id; } return QUuid(); } void LaserPointerManager::removeLaserPointer(const QUuid uid) { - QWriteLocker lock(&_removeLock); - _laserPointersToRemove.push(uid); + QWriteLocker lock(&_containsLock); + _laserPointers.remove(uid); + _laserPointerLocks.remove(uid); } void LaserPointerManager::enableLaserPointer(const QUuid uid) { @@ -69,32 +71,12 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) { } void LaserPointerManager::update() { + QReadLocker lock(&_containsLock); 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(); } - - QWriteLocker containsLock(&_containsLock); - { - QWriteLocker lock(&_addLock); - while (!_laserPointersToAdd.empty()) { - std::pair> laserPointerToAdd = _laserPointersToAdd.front(); - _laserPointersToAdd.pop(); - _laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second; - _laserPointerLocks[laserPointerToAdd.first] = std::make_shared(); - } - } - - { - QWriteLocker lock(&_removeLock); - while (!_laserPointersToRemove.empty()) { - QUuid uid = _laserPointersToRemove.front(); - _laserPointersToRemove.pop(); - _laserPointers.remove(uid); - _laserPointerLocks.remove(uid); - } - } } void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) { @@ -105,6 +87,14 @@ void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPic } } +void LaserPointerManager::setLaserLength(QUuid uid, const float laserLength) { + QReadLocker lock(&_containsLock); + if (_laserPointers.contains(uid)) { + QWriteLocker laserLock(_laserPointerLocks[uid].get()); + _laserPointers[uid]->setLaserLength(laserLength); + } +} + void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { QReadLocker lock(&_containsLock); if (_laserPointers.contains(uid)) { diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index b573410fe7..6494bb7056 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -32,6 +32,7 @@ public: const RayPickResult getPrevRayPickResult(const QUuid uid); void setPrecisionPicking(QUuid uid, const bool precisionPicking); + void setLaserLength(QUuid uid, const float laserLength); void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities); void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities); void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays); @@ -46,10 +47,6 @@ public: private: QHash> _laserPointers; QHash> _laserPointerLocks; - QReadWriteLock _addLock; - std::queue>> _laserPointersToAdd; - QReadWriteLock _removeLock; - std::queue _laserPointersToRemove; QReadWriteLock _containsLock; }; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index d65eb335b3..2f6da87b5f 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -31,6 +31,7 @@ public slots: Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); } Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking) { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); } + Q_INVOKABLE void setLaserLength(QUuid uid, const float laserLength) { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); } 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); } diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 04045b2116..0686a05718 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -70,6 +70,9 @@ public: if (doesPickNonCollidable()) { toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE); } + if (doesPickCourse()) { + toReturn |= getBitMask(PICK_COURSE); + } return Flags(toReturn); } Flags getOverlayFlags() const { @@ -80,6 +83,9 @@ public: if (doesPickNonCollidable()) { toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE); } + if (doesPickCourse()) { + toReturn |= getBitMask(PICK_COURSE); + } return Flags(toReturn); } Flags getAvatarFlags() const { return Flags(getBitMask(PICK_AVATARS)); } diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index 1ec8efc331..bfc6e3fcb2 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -38,11 +38,12 @@ void RayPickManager::cacheResult(const bool intersects, const RayPickResult& res res = resTemp; } } else { - cache[ray][mask] = RayPickResult(); + cache[ray][mask] = RayPickResult(res.searchRay); } } void RayPickManager::update() { + QReadLocker lock(&_containsLock); RayPickCache results; for (auto& uid : _rayPicks.keys()) { std::shared_ptr rayPick = _rayPicks[uid]; @@ -58,7 +59,7 @@ void RayPickManager::update() { } QPair rayKey = QPair(ray.origin, ray.direction); - RayPickResult res; + RayPickResult res = RayPickResult(ray); if (rayPick->getFilter().doesPickEntities()) { RayToEntityIntersectionResult entityRes; @@ -73,7 +74,7 @@ void RayPickManager::update() { } if (!fromCache) { - cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal), + cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal), entityMask, res, rayKey, results); } } @@ -91,7 +92,7 @@ void RayPickManager::update() { } if (!fromCache) { - cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal), + cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal), overlayMask, res, rayKey, results); } } @@ -100,7 +101,7 @@ void RayPickManager::update() { RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags(); if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) { 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); + cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarMask, res, rayKey, results); } } @@ -109,7 +110,7 @@ void RayPickManager::update() { 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), hudMask, res, rayKey, results); + cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudMask, res, rayKey, results); } } @@ -117,56 +118,39 @@ void RayPickManager::update() { 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.empty()) { - std::pair> rayPickToAdd = _rayPicksToAdd.front(); - _rayPicksToAdd.pop(); - _rayPicks[rayPickToAdd.first] = rayPickToAdd.second; - _rayPickLocks[rayPickToAdd.first] = std::make_shared(); - } - } - - { - QWriteLocker lock(&_removeLock); - while (!_rayPicksToRemove.empty()) { - QUuid uid = _rayPicksToRemove.front(); - _rayPicksToRemove.pop(); - _rayPicks.remove(uid); - _rayPickLocks.remove(uid); + rayPick->setRayPickResult(RayPickResult(ray)); } } } 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); + QWriteLocker lock(&_containsLock); QUuid id = QUuid::createUuid(); - _rayPicksToAdd.push(std::pair>(id, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled))); + _rayPicks[id] = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); + _rayPickLocks[id] = std::make_shared(); return id; } QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) { - QWriteLocker lock(&_addLock); + QWriteLocker lock(&_containsLock); QUuid id = QUuid::createUuid(); - _rayPicksToAdd.push(std::pair>(id, std::make_shared(filter, maxDistance, enabled))); + _rayPicks[id] = std::make_shared(filter, maxDistance, enabled); + _rayPickLocks[id] = std::make_shared(); return id; } QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) { - QWriteLocker lock(&_addLock); + QWriteLocker lock(&_containsLock); QUuid id = QUuid::createUuid(); - _rayPicksToAdd.push(std::pair>(id, std::make_shared(position, direction, filter, maxDistance, enabled))); + _rayPicks[id] = std::make_shared(position, direction, filter, maxDistance, enabled); + _rayPickLocks[id] = std::make_shared(); return id; } void RayPickManager::removeRayPick(const QUuid uid) { - QWriteLocker lock(&_removeLock); - _rayPicksToRemove.push(uid); + QWriteLocker lock(&_containsLock); + _rayPicks.remove(uid); + _rayPickLocks.remove(uid); } void RayPickManager::enableRayPick(const QUuid uid) { @@ -185,18 +169,6 @@ void RayPickManager::disableRayPick(const QUuid uid) { } } -const PickRay RayPickManager::getPickRay(const QUuid uid) { - QReadLocker containsLock(&_containsLock); - if (_rayPicks.contains(uid)) { - bool valid; - PickRay pickRay = _rayPicks[uid]->getPickRay(valid); - if (valid) { - return pickRay; - } - } - return PickRay(); -} - const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) { QReadLocker containsLock(&_containsLock); if (_rayPicks.contains(uid)) { diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index f2b1ff4ae4..9717767f19 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -28,7 +28,6 @@ class RayPickManager { public: void update(); - const PickRay getPickRay(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); @@ -49,10 +48,6 @@ public: private: QHash> _rayPicks; QHash> _rayPickLocks; - QReadWriteLock _addLock; - std::queue>> _rayPicksToAdd; - QReadWriteLock _removeLock; - std::queue _rayPicksToRemove; QReadWriteLock _containsLock; typedef QHash, std::unordered_map> RayPickCache; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 14e0ef5b28..5031016c3f 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -19,8 +19,13 @@ #include #include #include +#include #include +static const int AUTO_REFRESH_INTERVAL = 1000; + +int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); + AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.setSourceModel(&_assetMappingModel); _proxyModel.setSortRole(Qt::DisplayRole); @@ -189,6 +194,29 @@ void AssetMappingsScriptingInterface::setBakingEnabled(QStringList paths, bool e AssetMappingModel::AssetMappingModel() { setupRoles(); + + connect(&_autoRefreshTimer, &QTimer::timeout, this, [this] { + auto nodeList = DependencyManager::get(); + auto assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + if (assetServer) { + refresh(); + } + }); + _autoRefreshTimer.setInterval(AUTO_REFRESH_INTERVAL); +} + +bool AssetMappingModel::isAutoRefreshEnabled() { + return _autoRefreshTimer.isActive(); +} + +void AssetMappingModel::setAutoRefreshEnabled(bool enabled) { + if (enabled != _autoRefreshTimer.isActive()) { + if (enabled) { + _autoRefreshTimer.start(); + } else { + _autoRefreshTimer.stop(); + } + } } bool AssetMappingModel::isKnownFolder(QString path) const { @@ -205,10 +233,7 @@ bool AssetMappingModel::isKnownFolder(QString path) const { return false; } -int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); - void AssetMappingModel::refresh() { - qDebug() << "Refreshing asset mapping model"; auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index e4059c1ff7..04ab488838 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -25,11 +25,16 @@ class AssetMappingModel : public QStandardItemModel { Q_OBJECT + Q_PROPERTY(bool autoRefreshEnabled READ isAutoRefreshEnabled WRITE setAutoRefreshEnabled) + public: AssetMappingModel(); Q_INVOKABLE void refresh(); + bool isAutoRefreshEnabled(); + void setAutoRefreshEnabled(bool enabled); + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } bool isKnownFolder(QString path) const; @@ -44,6 +49,7 @@ private: void setupRoles(); QHash _pathToItemMap; + QTimer _autoRefreshTimer; }; Q_DECLARE_METATYPE(AssetMappingModel*) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 34aae37175..2366b888e7 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -15,6 +15,10 @@ #include #include +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + static const float CONTEXT_OVERLAY_TABLET_OFFSET = 30.0f; // Degrees static const float CONTEXT_OVERLAY_TABLET_ORIENTATION = 210.0f; // Degrees static const float CONTEXT_OVERLAY_TABLET_DISTANCE = 0.65F; // Meters @@ -38,11 +42,6 @@ ContextOverlayInterface::ContextOverlayInterface() { _entityPropertyFlags += PROP_DIMENSIONS; _entityPropertyFlags += PROP_REGISTRATION_POINT; - // initially, set _enabled to match the switch. Later we enable/disable via the getter/setters - // if we are in edit or pal (for instance). Note this is temporary, as we expect to enable this all - // the time after getting edge highlighting, etc... - _enabled = _settingSwitch.get(); - auto entityTreeRenderer = DependencyManager::get().data(); connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&))); connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&))); @@ -65,40 +64,36 @@ ContextOverlayInterface::ContextOverlayInterface() { connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged); } +static const uint32_t MOUSE_HW_ID = 0; static const uint32_t LEFT_HAND_HW_ID = 1; static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 }; static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters -static const float CONTEXT_OVERLAY_CLOSE_DISTANCE = 1.5f; // in meters -static const float CONTEXT_OVERLAY_CLOSE_SIZE = 0.12f; // in meters, same x and y dims -static const float CONTEXT_OVERLAY_FAR_SIZE = 0.08f; // in meters, same x and y dims -static const float CONTEXT_OVERLAY_CLOSE_OFFSET_ANGLE = 20.0f; +static const float CONTEXT_OVERLAY_SIZE = 0.09f; // in meters, same x and y dims +static const float CONTEXT_OVERLAY_OFFSET_DISTANCE = 0.1f; +static const float CONTEXT_OVERLAY_OFFSET_ANGLE = 5.0f; static const float CONTEXT_OVERLAY_UNHOVERED_ALPHA = 0.85f; static const float CONTEXT_OVERLAY_HOVERED_ALPHA = 1.0f; static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMIN = 0.6f; static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMAX = 1.0f; static const float CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD = 1.0f; static const float CONTEXT_OVERLAY_UNHOVERED_COLORPULSE = 1.0f; -static const float CONTEXT_OVERLAY_FAR_OFFSET = 0.1f; void ContextOverlayInterface::setEnabled(bool enabled) { - // only enable/disable if the setting in 'on'. If it is 'off', - // make sure _enabled is always false. - if (_settingSwitch.get()) { - _enabled = enabled; - } else { - _enabled = false; - } + _enabled = enabled; } bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) { if (_enabled && event.getButton() == PointerEvent::SecondaryButton) { if (contextOverlayFilterPassed(entityItemID)) { + if (event.getID() == MOUSE_HW_ID) { + enableEntityHighlight(entityItemID); + } + qCDebug(context_overlay) << "Creating Context Overlay on top of entity with ID: " << entityItemID; // Add all necessary variables to the stack EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags); glm::vec3 cameraPosition = qApp->getCamera().getPosition(); - float distanceFromCameraToEntity = glm::distance(entityProperties.getPosition(), cameraPosition); glm::vec3 entityDimensions = entityProperties.getDimensions(); glm::vec3 entityPosition = entityProperties.getPosition(); glm::vec3 contextOverlayPosition = entityProperties.getPosition(); @@ -131,27 +126,22 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& // If the camera is inside the box... // ...position the Context Overlay 1 meter in front of the camera. contextOverlayPosition = cameraPosition + CONTEXT_OVERLAY_INSIDE_DISTANCE * (qApp->getCamera().getOrientation() * Vectors::FRONT); - contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_CLOSE_SIZE, CONTEXT_OVERLAY_CLOSE_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); - } else if (distanceFromCameraToEntity < CONTEXT_OVERLAY_CLOSE_DISTANCE) { - // Else if the entity is too close to the camera... - // ...rotate the Context Overlay to the right of the entity. - // This makes it easy to inspect things you're holding. - float offsetAngle = -CONTEXT_OVERLAY_CLOSE_OFFSET_ANGLE; - if (event.getID() == LEFT_HAND_HW_ID) { - offsetAngle *= -1; - } - contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f))) * (entityPosition - cameraPosition)) + cameraPosition; - contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_CLOSE_SIZE, CONTEXT_OVERLAY_CLOSE_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); + contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); } else { - // Else, place the Context Overlay some offset away from the entity's bounding - // box in the direction of the camera. + // Rotate the Context Overlay some number of degrees offset from the entity + // along the line cast from your head to the entity's bounding box. glm::vec3 direction = glm::normalize(entityPosition - cameraPosition); float distance; BoxFace face; glm::vec3 normal; boundingBox.findRayIntersection(cameraPosition, direction, distance, face, normal); - contextOverlayPosition = (cameraPosition + direction * distance) - direction * CONTEXT_OVERLAY_FAR_OFFSET; - contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_FAR_SIZE, CONTEXT_OVERLAY_FAR_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); + float offsetAngle = -CONTEXT_OVERLAY_OFFSET_ANGLE; + if (event.getID() == LEFT_HAND_HW_ID) { + offsetAngle *= -1; + } + contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) * + ((cameraPosition + direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE))); + contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); } // Finally, setup and draw the Context Overlay @@ -176,6 +166,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& } } else { if (!_currentEntityWithContextOverlay.isNull()) { + disableEntityHighlight(_currentEntityWithContextOverlay); return destroyContextOverlay(_currentEntityWithContextOverlay, event); } return false; @@ -237,13 +228,13 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID& } void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) { - if (contextOverlayFilterPassed(entityID)) { + if (contextOverlayFilterPassed(entityID) && _enabled && event.getID() != MOUSE_HW_ID) { enableEntityHighlight(entityID); } } void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event) { - if (_currentEntityWithContextOverlay != entityID) { + if (_currentEntityWithContextOverlay != entityID && _enabled && event.getID() != MOUSE_HW_ID) { disableEntityHighlight(entityID); } } diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index c14262029e..fddd1fcdb5 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -76,8 +76,6 @@ private: bool _isInMarketplaceInspectionMode { false }; - Setting::Handle _settingSwitch { "inspectionMode", false }; - void openMarketplace(); void enableEntityHighlight(const EntityItemID& entityItemID); void disableEntityHighlight(const EntityItemID& entityItemID); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index f8c40a5229..0cb25a2e2f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -222,6 +222,16 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene _renderablesToUpdate.insert({ entityId, renderable }); } + // NOTE: Looping over all the entity renderers is likely to be a bottleneck in the future + // Currently, this is necessary because the model entity loading logic requires constant polling + // This was working fine because the entity server used to send repeated updates as your view changed, + // but with the improved entity server logic (PR 11141), updateInScene (below) would not be triggered enough + for (const auto& entry : _entitiesInScene) { + const auto& renderable = entry.second; + if (renderable) { + renderable->update(scene, transaction); + } + } if (!_renderablesToUpdate.empty()) { for (const auto& entry : _renderablesToUpdate) { const auto& renderable = entry.second; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 3f1e89b86c..ea514d3181 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -291,6 +291,18 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans }); } +void EntityRenderer::update(const ScenePointer& scene, Transaction& transaction) { + if (!isValidRenderItem()) { + return; + } + + if (!needsUpdate()) { + return; + } + + doUpdate(scene, transaction, _entity); +} + // // Internal methods // @@ -304,6 +316,11 @@ bool EntityRenderer::needsRenderUpdate() const { return needsRenderUpdateFromEntity(_entity); } +// Returns true if the item needs to have update called +bool EntityRenderer::needsUpdate() const { + return needsUpdateFromEntity(_entity); +} + // Returns true if the item in question needs to have updateInScene called because of changes in the entity bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity) const { bool success = false; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 6b47ff8b1d..56cb39252f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -49,6 +49,8 @@ public: virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final; virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction); + virtual void update(const ScenePointer& scene, Transaction& transaction); + protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } virtual void onAddToScene(const EntityItemPointer& entity); @@ -71,6 +73,12 @@ protected: // Returns true if the item in question needs to have updateInScene called because of changes in the entity virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const; + // Returns true if the item in question needs to have update called + virtual bool needsUpdate() const; + + // Returns true if the item in question needs to have update called because of changes in the entity + virtual bool needsUpdateFromEntity(const EntityItemPointer& entity) const { return false; } + // Will be called on the main thread from updateInScene. This can be used to fetch things like // network textures or model geometry from resource caches virtual void doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { } @@ -80,6 +88,8 @@ protected: // data in this method if using multi-threaded rendering virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity); + virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { } + // Called by the `render` method after `needsRenderUpdate` virtual void doRender(RenderArgs* args) = 0; @@ -148,6 +158,15 @@ protected: onRemoveFromSceneTyped(_typedEntity); } + using Parent::needsUpdateFromEntity; + // Returns true if the item in question needs to have update called because of changes in the entity + virtual bool needsUpdateFromEntity(const EntityItemPointer& entity) const override final { + if (Parent::needsUpdateFromEntity(entity)) { + return true; + } + return needsUpdateFromTypedEntity(_typedEntity); + } + using Parent::needsRenderUpdateFromEntity; // Returns true if the item in question needs to have updateInScene called because of changes in the entity virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const override final { @@ -162,6 +181,11 @@ protected: doRenderUpdateSynchronousTyped(scene, transaction, _typedEntity); } + virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) override final { + Parent::doUpdate(scene, transaction, entity); + doUpdateTyped(scene, transaction, _typedEntity); + } + virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) override final { Parent::doRenderUpdateAsynchronous(entity); doRenderUpdateAsynchronousTyped(_typedEntity); @@ -170,6 +194,8 @@ protected: virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; } virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { } virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { } + virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; } + virtual void doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { } virtual void onAddToSceneTyped(const TypedEntityPointer& entity) { } virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) { } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2508b598af..799a84aaee 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -904,7 +904,7 @@ using namespace render; using namespace render::entities; ItemKey ModelEntityRenderer::getKey() { - return ItemKey::Builder::opaqueShape().withTypeMeta(); + return ItemKey::Builder().withTypeMeta(); } uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { @@ -1026,12 +1026,16 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { entity->copyAnimationJointDataToModel(); } -bool ModelEntityRenderer::needsRenderUpdate() const { +bool ModelEntityRenderer::needsUpdate() const { ModelPointer model; withReadLock([&] { model = _model; }); + if (_modelJustLoaded) { + return true; + } + if (model) { if (_needsJointSimulation || _moving || _animating) { return true; @@ -1057,10 +1061,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const { return true; } } - return Parent::needsRenderUpdate(); + return Parent::needsUpdate(); } -bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { +bool ModelEntityRenderer::needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const { if (resultWithReadLock([&] { if (entity->hasModel() != _hasModel) { return true; @@ -1122,7 +1126,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return false; } -void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { +void ModelEntityRenderer::doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { if (_hasModel != entity->hasModel()) { _hasModel = entity->hasModel(); } @@ -1148,9 +1152,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce return; } + _modelJustLoaded = false; // Check for addition if (_hasModel && !(bool)_model) { model = std::make_shared(nullptr, entity.get()); + connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::handleModelLoaded); model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); model->init(); entity->setModel(model); @@ -1175,8 +1181,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it auto extents = model->getMeshExtents(); properties.setDimensions(extents.maximum - extents.minimum); - qCDebug(entitiesrenderer) << "Autoresizing" - << (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL()) + qCDebug(entitiesrenderer) << "Autoresizing" + << (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL()) << "from mesh extents"; QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", @@ -1203,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce entity->updateModelBounds(); } - if (model->isVisible() != _visible) { // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state @@ -1234,7 +1239,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce }); } - if (_animating) { if (!jointsMapped()) { mapJoints(entity, model->getJointNames()); @@ -1243,6 +1247,12 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } } +void ModelEntityRenderer::handleModelLoaded(bool success) { + if (success) { + _modelJustLoaded = true; + } +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index b9c751761d..ad0afeee0a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -138,10 +138,10 @@ protected: virtual ItemKey getKey() override; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; - virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; - virtual bool needsRenderUpdate() const override; + virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual bool needsUpdate() const override; virtual void doRender(RenderArgs* args) override; - virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; private: void animate(const TypedEntityPointer& entity); @@ -151,6 +151,7 @@ private: // Transparency is handled in ModelMeshPartPayload virtual bool isTransparent() const override { return false; } + bool _modelJustLoaded { false }; bool _hasModel { false }; ::ModelPointer _model; GeometryResource::Pointer _compoundShapeResource; @@ -178,6 +179,9 @@ private: bool _animating { false }; uint64_t _lastAnimated { 0 }; float _currentFrame { 0 }; + +private slots: + void handleModelLoaded(bool success); }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 8757bcbb0f..f4e4c0ea8f 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -102,7 +102,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); transformToTopLeft.setRotation(orientation); } - transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left + transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed batch.setModelTransform(transformToTopLeft); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 8b5feb15f0..5dc75dad08 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -140,6 +140,11 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene _webSurface->resize(QSize(windowSize.x, windowSize.y)); } +void WebEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { + Parent::doRenderUpdateAsynchronousTyped(entity); + _modelTransform.postScale(entity->getDimensions()); +} + void WebEntityRenderer::doRender(RenderArgs* args) { withWriteLock([&] { _lastRenderTime = usecTimestampNow(); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 4b7e7e25a1..a67eb39670 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -29,6 +29,7 @@ protected: virtual bool needsRenderUpdate() const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRender(RenderArgs* args) override; virtual bool isTransparent() const override; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 468d22ce9e..74c8d06736 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -464,7 +464,7 @@ void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) { _resource = resource; if (_resource) { if (_resource->isLoaded()) { - _geometryRef = std::make_shared(*_resource); + resourceFinished(true); } else { startWatching(); } diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index d2da521768..32e764bd10 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -120,7 +120,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { _dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR); _dynamicsWorld->addAction(this); // restore gravity settings because adding an object to the world overwrites its gravity setting - _rigidBody->setGravity(_gravity * _currentUp); + _rigidBody->setGravity(_currentGravity * _currentUp); btCollisionShape* shape = _rigidBody->getCollisionShape(); assert(shape && shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE); _ghost.setCharacterShape(static_cast(shape)); @@ -302,7 +302,7 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // add minimum velocity to counteract gravity's displacement during one step // Note: the 0.5 factor comes from the fact that we really want the // average velocity contribution from gravity during the step - stepUpSpeed -= 0.5f * _gravity * timeToStep; // remember: _gravity is negative scalar + stepUpSpeed -= 0.5f * _currentGravity * timeToStep; // remember: _gravity is negative scalar btScalar vDotUp = velocity.dot(_currentUp); if (vDotUp < stepUpSpeed) { @@ -351,6 +351,28 @@ static const char* stateToStr(CharacterController::State state) { } #endif // #ifdef DEBUG_STATE_CHANGE +void CharacterController::updateCurrentGravity() { + int16_t collisionGroup = computeCollisionGroup(); + if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) { + _currentGravity = 0.0f; + } else { + _currentGravity = _gravity; + } + if (_rigidBody) { + _rigidBody->setGravity(_currentGravity * _currentUp); + } +} + + +void CharacterController::setGravity(float gravity) { + _gravity = gravity; + updateCurrentGravity(); +} + +float CharacterController::getGravity() { + return _gravity; +} + #ifdef DEBUG_STATE_CHANGE void CharacterController::setState(State desiredState, const char* reason) { #else @@ -365,19 +387,7 @@ void CharacterController::setState(State desiredState) { qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason; #endif _state = desiredState; - updateGravity(); - } -} - -void CharacterController::updateGravity() { - int16_t collisionGroup = computeCollisionGroup(); - if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) { - _gravity = 0.0f; - } else { - _gravity = DEFAULT_AVATAR_GRAVITY; - } - if (_rigidBody) { - _rigidBody->setGravity(_gravity * _currentUp); + updateCurrentGravity(); } } @@ -436,14 +446,14 @@ void CharacterController::handleChangedCollisionGroup() { _dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR); } _pendingFlags &= ~PENDING_FLAG_UPDATE_COLLISION_GROUP; - updateGravity(); + updateCurrentGravity(); } } void CharacterController::updateUpAxis(const glm::quat& rotation) { _currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS); if (_rigidBody) { - _rigidBody->setGravity(_gravity * _currentUp); + _rigidBody->setGravity(_currentGravity * _currentUp); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 585eb7d3ed..0f97cc7c16 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -24,6 +24,7 @@ #include "BulletUtil.h" #include "CharacterGhostObject.h" +#include "AvatarConstants.h" const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; @@ -42,15 +43,18 @@ const btScalar MAX_CHARACTER_MOTOR_TIMESCALE = 60.0f; // one minute const btScalar MIN_CHARACTER_MOTOR_TIMESCALE = 0.05f; class CharacterController : public btCharacterControllerInterface { + public: CharacterController(); virtual ~CharacterController(); - bool needsRemoval() const; bool needsAddition() const; virtual void setDynamicsWorld(btDynamicsWorld* world); btCollisionObject* getCollisionObject() { return _rigidBody; } + void setGravity(float gravity); + float getGravity(); + virtual void updateShapeIfNecessary() = 0; // overrides from btCharacterControllerInterface @@ -131,7 +135,7 @@ protected: #endif virtual void updateMassProperties() = 0; - void updateGravity(); + void updateCurrentGravity(); void updateUpAxis(const glm::quat& rotation); bool checkForSupport(btCollisionWorld* collisionWorld); @@ -184,7 +188,8 @@ protected: bool _stepUpEnabled { true }; bool _hasSupport; - btScalar _gravity { 0.0f }; + btScalar _currentGravity { 0.0f }; + btScalar _gravity { DEFAULT_AVATAR_GRAVITY }; btScalar _followTime; btVector3 _followLinearDisplacement; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 517fe97dba..3f57a1779a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -321,17 +321,25 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } -ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : - _meshIndex(_meshIndex), +ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : + _meshIndex(meshIndex), _shapeID(shapeIndex) { assert(model && model->isLoaded()); _model = model; auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); + const Model::MeshState& state = model->getMeshState(_meshIndex); updateMeshPart(modelMesh, partIndex); + computeAdjustedLocalBound(state.clusterMatrices); updateTransform(transform, offsetTransform); + Transform renderTransform = transform; + if (state.clusterMatrices.size() == 1) { + renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); + } + updateTransformForSkinnedMesh(renderTransform, transform, state.clusterBuffer); + initCache(); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 1f45647c0d..f25cad8a6e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -209,11 +209,6 @@ void Model::updateRenderItems() { return; } - glm::vec3 scale = getScale(); - if (_collisionGeometry) { - // _collisionGeometry is already scaled - scale = glm::vec3(1.0f); - } _needsUpdateClusterMatrices = true; _renderItemsNeedUpdate = false; @@ -221,7 +216,7 @@ void Model::updateRenderItems() { // the application will ensure only the last lambda is actually invoked. void* key = (void*)this; std::weak_ptr weakSelf = shared_from_this(); - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() { // do nothing, if the model has already been destroyed. auto self = weakSelf.lock(); @@ -1220,6 +1215,7 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { } void Model::createRenderItemSet() { + updateClusterMatrices(); if (_collisionGeometry) { if (_collisionRenderItems.empty()) { createCollisionRenderItemSet(); @@ -1270,7 +1266,6 @@ void Model::createVisibleRenderItemSet() { shapeID++; } } - computeMeshPartLocalBounds(); } void Model::createCollisionRenderItemSet() { diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index 36dc59f29e..f88092429f 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -81,10 +81,10 @@ public: float getColorB() const { return color.b; } glm::vec3 color{ 1.f, 0.7f, 0.2f }; - float width{ 3.f }; - float intensity{ 1.f }; - float fillOpacityUnoccluded{ 0.35f }; - float fillOpacityOccluded{ 0.1f }; + float width{ 2.0f }; + float intensity{ 0.9f }; + float fillOpacityUnoccluded{ 0.0f }; + float fillOpacityOccluded{ 0.0f }; bool glow{ false }; signals: diff --git a/libraries/render-utils/src/glowLine.slf b/libraries/render-utils/src/glowLine.slf index c0af97930a..580a49dd3e 100644 --- a/libraries/render-utils/src/glowLine.slf +++ b/libraries/render-utils/src/glowLine.slf @@ -9,7 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(location = 0) in vec4 inColor; +in vec4 _color; +in float distanceFromCenter; out vec4 _fragColor; @@ -17,10 +18,10 @@ void main(void) { // The incoming value actually ranges from -1 to 1, so modify it // so that it goes from 0 -> 1 -> 0 with the solid alpha being at // the center of the line - float alpha = 1.0 - abs(inColor.a); + float alpha = 1.0 - abs(distanceFromCenter); // Convert from a linear alpha curve to a sharp peaked one - alpha = pow(alpha, 10); + alpha = _color.a * pow(alpha, 10); // Drop everything where the curve falls off to nearly nothing if (alpha <= 0.05) { @@ -28,6 +29,5 @@ void main(void) { } // Emit the color - _fragColor = vec4(inColor.rgb, alpha); - return; + _fragColor = vec4(_color.rgb, alpha); } diff --git a/libraries/render-utils/src/glowLine.slv b/libraries/render-utils/src/glowLine.slv index e856edc787..fd3a85d254 100644 --- a/libraries/render-utils/src/glowLine.slv +++ b/libraries/render-utils/src/glowLine.slv @@ -18,7 +18,9 @@ layout(std140) uniform lineData { vec4 color; }; -layout(location = 0) out vec4 _color; +out vec4 _color; +// the distance from the center in 'quad space' +out float distanceFromCenter; void main(void) { _color = color; @@ -45,11 +47,10 @@ void main(void) { // Add or subtract the orthogonal vector based on a different vertex ID // calculation if (gl_VertexID < 2) { - // Use the alpha channel to store the distance from the center in 'quad space' - _color.a = -1.0; + distanceFromCenter = -1.0; eye.xyz -= orthogonal; } else { - _color.a = 1.0; + distanceFromCenter = 1.0; eye.xyz += orthogonal; } diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 228560f394..0dd10b8e1e 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -75,7 +75,7 @@ void main(void) { max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, - specular); + vec3(clamp(emissiveAmount, 0.0, 1.0))); } else { packDeferredFragment( normal, diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/shared/src/PointerEvent.cpp index 7ec5e78b9f..e35832391d 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/shared/src/PointerEvent.cpp @@ -77,13 +77,13 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve normal.setProperty("x", event._normal.x); normal.setProperty("y", event._normal.y); normal.setProperty("z", event._normal.z); - obj.setProperty("pos3D", normal); + obj.setProperty("normal", normal); QScriptValue direction = engine->newObject(); direction.setProperty("x", event._direction.x); direction.setProperty("y", event._direction.y); direction.setProperty("z", event._direction.z); - obj.setProperty("pos3D", direction); + obj.setProperty("direction", direction); bool isPrimaryButton = false; bool isSecondaryButton = false; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 8257c883a2..7d0df3ac78 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -762,6 +762,8 @@ QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResu QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection); obj.setProperty("intersection", intersection); obj.setProperty("intersects", rayPickResult.type != NONE); + QScriptValue searchRay = pickRayToScriptValue(engine, rayPickResult.searchRay); + obj.setProperty("searchRay", searchRay); QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal); obj.setProperty("surfaceNormal", surfaceNormal); return obj; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index ed928a6e7b..7b7d8d8f47 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -137,7 +137,7 @@ QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); enum IntersectionType { - NONE, + NONE = 0, ENTITY, OVERLAY, AVATAR, @@ -147,12 +147,14 @@ enum IntersectionType { class RayPickResult { public: RayPickResult() {} - 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) {} + RayPickResult(const PickRay& searchRay) : searchRay(searchRay) {} + RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + type(type), objectID(objectID), distance(distance), intersection(intersection), searchRay(searchRay), surfaceNormal(surfaceNormal) {} IntersectionType type { NONE }; - QUuid objectID { 0 }; + QUuid objectID; float distance { FLT_MAX }; glm::vec3 intersection { NAN }; + PickRay searchRay; glm::vec3 surfaceNormal { NAN }; }; Q_DECLARE_METATYPE(RayPickResult) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index faf7933d1a..071ccd46b1 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -211,12 +211,12 @@ class UrlHandler : public QObject { public: Q_INVOKABLE bool canHandleUrl(const QString& url) { static auto handler = dynamic_cast(qApp); - return handler->canAcceptURL(url); + return handler && handler->canAcceptURL(url); } Q_INVOKABLE bool handleUrl(const QString& url) { static auto handler = dynamic_cast(qApp); - return handler->acceptURL(url); + return handler && handler->acceptURL(url); } }; diff --git a/libraries/ui/src/ui/types/RequestFilters.cpp b/libraries/ui/src/ui/types/RequestFilters.cpp index 6ef3effa4c..233a9458fe 100644 --- a/libraries/ui/src/ui/types/RequestFilters.cpp +++ b/libraries/ui/src/ui/types/RequestFilters.cpp @@ -61,7 +61,7 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) // 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 }; + static Setting::Handle _settingSwitch{ "commerce", false }; bool isMoney = _settingSwitch.get(); const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse); diff --git a/scripts/developer/tests/gravityScript.js b/scripts/developer/tests/gravityScript.js new file mode 100644 index 0000000000..3468de72c3 --- /dev/null +++ b/scripts/developer/tests/gravityScript.js @@ -0,0 +1,45 @@ +// +// Gravity Script 1.0 +// ************ +// +// Created by Cain Kilgore on 9/14/2017 + +// Javascript for the Gravity Modifier Implementation to test +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +function menuParameters(menuNameSelection, menuItemNameSelection) { + Menu.addMenuItem({ + menuName: menuNameSelection, + menuItemName: menuItemNameSelection, + isCheckable: false + }); +} + +function setupMenu() { + if (!Menu.menuExists("Gravity")) { + Menu.addMenu("Gravity"); + for (var i = -5; i <= 5; i++) { + menuParameters("Gravity", i); + } + } +} + +function menuItemEvent(menuItem) { + for (var i = -5; i <= 5; i++) { + if (menuItem == i) { + MyAvatar.setGravity(i); + } + } +} + +function onScriptEnding() { + Menu.removeMenu("Gravity"); +} + +setupMenu(); +Menu.menuItemEvent.connect(menuItemEvent); +Script.scriptEnding.connect(onScriptEnding); diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 5a668a3d6e..107160154a 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -131,7 +131,7 @@ var button; var buttonName = "WALLET"; var tablet = null; - var walletEnabled = Settings.getValue("inspectionMode", false); + var walletEnabled = Settings.getValue("commerce", false); function startup() { if (walletEnabled) { tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index eb73b0f908..d2b5f92fde 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -148,7 +148,9 @@ Script.include("/~/system/libraries/controllers.js"); if (mode === "full") { var fullEndToEdit = PICK_WITH_HAND_RAY ? this.fullEnd : fullEnd; fullEndToEdit.dimensions = dim; - LaserPointers.editRenderState(laserPointerID, mode, {path: fullPath, end: fullEndToEdit}); + LaserPointers.editRenderState(laserPointerID, mode, { path: fullPath, end: fullEndToEdit }); + this.contextOverlayTimer = false; + this.destroyContextOverlay(); } else if (mode === "half") { var halfEndToEdit = PICK_WITH_HAND_RAY ? this.halfEnd : halfEnd; halfEndToEdit.dimensions = dim; diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index e08b61dbd5..39e9371931 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -44,10 +44,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); return (this.hand === RIGHT_HAND) ? leftNearParentingGrabEntity : rightNearParentingGrabEntity; }; - this.otherHandIsParent = function(props) { - return this.getOtherModule().thisHandIsParent(props); - }; - this.thisHandIsParent = function(props) { if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) { return false; @@ -99,12 +95,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); // this should never happen, but if it does, don't set previous parent to be this hand. // this.previousParentID[targetProps.id] = NULL; // this.previousParentJointIndex[targetProps.id] = -1; - } else if (this.otherHandIsParent(targetProps)) { - // the other hand is parent. Steal the object and information - var otherModule = this.getOtherModule(); - this.previousParentID[targetProps.id] = otherModule.previousParentID[targetProps.id]; - this.previousParentJointIndex[targetProps.id] = otherModule.previousParentJointIndex[targetProps.id]; - otherModule.endNearParentingGrabEntity(); } else { this.previousParentID[targetProps.id] = targetProps.parentID; this.previousParentJointIndex[targetProps.id] = targetProps.parentJointIndex; diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index d67672ca7c..7dace85ec4 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -298,6 +298,9 @@ Script.include("/~/system/libraries/controllers.js"); var intersection = controllerData.rayPicks[this.hand]; var offOverlay = (intersection.type !== RayPick.INTERSECTED_OVERLAY); var triggerOff = (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE); + if (triggerOff) { + this.deleteContextOverlay(); + } var grabbingOverlay = this.grabModuleWantsNearbyOverlay(controllerData); return offOverlay || grabbingOverlay || triggerOff; }; @@ -308,7 +311,6 @@ Script.include("/~/system/libraries/controllers.js"); this.laserPressExit(); this.laserPressingTarget = false; } - this.deleteContextOverlay(); this.relinquishTouchFocus(); this.reset(); this.updateLaserPointer(); diff --git a/scripts/system/controllers/controllerModules/scaleAvatar.js b/scripts/system/controllers/controllerModules/scaleAvatar.js index 05804c967b..fc28f4a00f 100644 --- a/scripts/system/controllers/controllerModules/scaleAvatar.js +++ b/scripts/system/controllers/controllerModules/scaleAvatar.js @@ -1,4 +1,4 @@ -// handControllerGrab.js +// scaleAvatar.js // // Created by Dante Ruiz on 9/11/17 // @@ -80,4 +80,5 @@ dispatcherUtils.disableDispatcherModule("LeftScaleAvatar"); dispatcherUtils.disableDispatcherModule("RightScaleAvatar"); }; + Script.scriptEnding.connect(this.cleanup); })(); diff --git a/scripts/system/controllers/controllerModules/scaleEntity.js b/scripts/system/controllers/controllerModules/scaleEntity.js new file mode 100644 index 0000000000..79b1d18db9 --- /dev/null +++ b/scripts/system/controllers/controllerModules/scaleEntity.js @@ -0,0 +1,106 @@ +// scaleEntity.js +// +// Created by Dante Ruiz on 9/18/17 +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +/* global Script, Vec3, MyAvatar, RIGHT_HAND */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ + +(function() { + var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); + + function ScaleEntity(hand) { + this.hand = hand; + this.grabbedThingID = false; + this.scalingStartDistance = false; + this.scalingStartDimensions = false; + + this.parameters = dispatcherUtils.makeDispatcherModuleParameters( + 120, + this.hand === RIGHT_HAND ? ["rightHandTrigger"] : ["leftHandTrigger"], + [], + 100 + ); + + this.otherHand = function() { + return this.hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND : dispatcherUtils.RIGHT_HAND; + }; + + this.otherModule = function() { + return this.hand === dispatcherUtils.RIGHT_HAND ? leftScaleEntity : rightScaleEntity; + }; + + this.bumperPressed = function(controllerData) { + return ( controllerData.secondaryValues[this.hand] > dispatcherUtils.BUMPER_ON_VALUE); + }; + + this.getTargetProps = function(controllerData) { + // nearbyEntityProperties is already sorted by length from controller + var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; + var sensorScaleFactor = MyAvatar.sensorToWorldScale; + for (var i = 0; i < nearbyEntityProperties.length; i++) { + var props = nearbyEntityProperties[i]; + var handPosition = controllerData.controllerLocations[this.hand].position; + var distance = Vec3.distance(props.position, handPosition); + if (distance > dispatcherUtils.NEAR_GRAB_RADIUS * sensorScaleFactor) { + continue; + } + if ((dispatcherUtils.entityIsGrabbable(props) || + dispatcherUtils.propsArePhysical(props)) && !props.locked) { + return props; + } + } + return null; + }; + + this.isReady = function(controllerData) { + var otherModule = this.otherModule(); + if (this.bumperPressed(controllerData) && otherModule.bumperPressed(controllerData)) { + var thisHandTargetProps = this.getTargetProps(controllerData); + var otherHandTargetProps = otherModule.getTargetProps(controllerData); + if (thisHandTargetProps && otherHandTargetProps) { + if (thisHandTargetProps.id === otherHandTargetProps.id) { + this.grabbedThingID = thisHandTargetProps.id; + this.scalingStartDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, + controllerData.controllerLocations[this.otherHand()].position)); + this.scalingStartDimensions = thisHandTargetProps.dimensions; + return dispatcherUtils.makeRunningValues(true, [], []); + } + } + } + return dispatcherUtils.makeRunningValues(false, [], []); + }; + + this.run = function(controllerData) { + var otherModule = this.otherModule(); + if (this.bumperPressed(controllerData) && otherModule.bumperPressed(controllerData)) { + if (this.hand === dispatcherUtils.RIGHT_HAND) { + var scalingCurrentDistance = + Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, + controllerData.controllerLocations[this.otherHand()].position)); + var currentRescale = scalingCurrentDistance / this.scalingStartDistance; + var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions); + Entities.editEntity(this.grabbedThingID, { dimensions: newDimensions }); + } + return dispatcherUtils.makeRunningValues(true, [], []); + } + return dispatcherUtils.makeRunningValues(false, [], []); + }; + } + + var leftScaleEntity = new ScaleEntity(dispatcherUtils.LEFT_HAND); + var rightScaleEntity = new ScaleEntity(dispatcherUtils.RIGHT_HAND); + + dispatcherUtils.enableDispatcherModule("LeftScaleEntity", leftScaleEntity); + dispatcherUtils.enableDispatcherModule("RightScaleEntity", rightScaleEntity); + + this.cleanup = function() { + dispatcherUtils.disableDispatcherModule("LeftScaleEntity"); + dispatcherUtils.disableDispatcherModule("RightScaleEntity"); + }; + Script.scriptEnding.connect(this.cleanup); +})(); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index e8b07c623d..6b140173b8 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -29,7 +29,8 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/disableOtherModule.js", "controllerModules/farTrigger.js", "controllerModules/teleport.js", - "controllerModules/scaleAvatar.js" + "controllerModules/scaleAvatar.js", + "controllerModules/scaleEntity.js" ]; var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 84c26d482b..138e3a3956 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -450,7 +450,7 @@ var parsedJsonMessage = JSON.parse(message); if (parsedJsonMessage.type === "marketplaces") { - if (parsedJsonMessage.action === "inspectionModeSetting") { + if (parsedJsonMessage.action === "commerceSetting") { confirmAllPurchases = !!parsedJsonMessage.data; injectCode(); } @@ -458,7 +458,7 @@ } }); - // Request inspection mode setting + // Request commerce setting // Code is injected into the webpage after the setting comes back. EventBridge.emitWebEvent(JSON.stringify({ type: "REQUEST_SETTING" diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 10931e4e93..f7a08f3abb 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -319,7 +319,11 @@ if (typeof module !== 'undefined') { LEFT_HAND: LEFT_HAND, RIGHT_HAND: RIGHT_HAND, BUMPER_ON_VALUE: BUMPER_ON_VALUE, + propsArePhysical: propsArePhysical, + entityIsGrabbable: entityIsGrabbable, + NEAR_GRAB_RADIUS: NEAR_GRAB_RADIUS, projectOntoOverlayXYPlane: projectOntoOverlayXYPlane, projectOntoEntityXYPlane: projectOntoEntityXYPlane + }; } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 2eaefe7565..7ae0aa3390 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -138,8 +138,8 @@ } else if (parsedJsonMessage.type === "REQUEST_SETTING") { tablet.emitScriptEvent(JSON.stringify({ type: "marketplaces", - action: "inspectionModeSetting", - data: Settings.getValue("inspectionMode", false) + action: "commerceSetting", + data: Settings.getValue("commerce", false) })); } else if (parsedJsonMessage.type === "PURCHASES") { tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 77c8ab2177..5b83ff313b 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -12,7 +12,7 @@ setup_hifi_project(Quick Gui OpenGL) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries -link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi) +link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi ui) package_libraries_for_deployment() diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 3be6ba2f6c..58eb4d16f9 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -42,11 +42,15 @@ #include #include +#include + #include #include #include #include +#include + #include #include #include @@ -427,6 +431,10 @@ namespace render { } } +OffscreenGLCanvas* _chromiumShareContext{ nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); + + // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow, public AbstractViewStateInterface { @@ -506,8 +514,6 @@ public: AbstractViewStateInterface::setInstance(this); _octree = DependencyManager::set(false, this, nullptr); _octree->init(); - // Prevent web entities from rendering - REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory); DependencyManager::set(_octree->getTree()); auto nodeList = DependencyManager::get(); @@ -535,6 +541,23 @@ public: _renderThread.initialize(this, _initContext); _initContext.makeCurrent(); + if (nsightActive()) { + // Prevent web entities from rendering + REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory); + } else { + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->setObjectName("ChromiumShareContext"); + _chromiumShareContext->create(_initContext.qglContext()); + _chromiumShareContext->makeCurrent(); + qt_gl_set_global_share_context(_chromiumShareContext->getContext()); + + // Make sure all QML surfaces share the main thread GL context + OffscreenQmlSurface::setSharedContext(_initContext.qglContext()); + + _initContext.makeCurrent(); + } + + // FIXME use a wait condition QThread::msleep(1000); _renderThread.submitFrame(gpu::FramePointer()); @@ -679,6 +702,7 @@ private: _renderCount = _renderThread._presentCount.load(); update(); + _initContext.makeCurrent(); RenderArgs renderArgs(_renderThread._gpuContext, DEFAULT_OCTREE_SIZE_SCALE, 0, RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);