From 95a565627c1fe50e00bf66a90ae5dd16df651afa Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 14 May 2015 08:49:44 -0700 Subject: [PATCH 01/11] Make DDE isTracking() behave the same as Faceshift's --- interface/src/devices/DdeFaceTracker.cpp | 4 ++++ interface/src/devices/DdeFaceTracker.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index ca2f5bd48e..9ed750bb34 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -293,6 +293,10 @@ void DdeFaceTracker::reset() { } bool DdeFaceTracker::isActive() const { + return (_ddeProcess != NULL); +} + +bool DdeFaceTracker::isTracking() const { static const quint64 ACTIVE_TIMEOUT_USECS = 3000000; //3 secs return (usecTimestampNow() - _lastReceiveTimestamp < ACTIVE_TIMEOUT_USECS); } diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index c44de897e9..b3318d0cb0 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -33,7 +33,7 @@ public: virtual void reset(); virtual bool isActive() const; - virtual bool isTracking() const { return isActive(); } + virtual bool isTracking() const; float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } From ff7b2016b4607282189e8bba70bf70f98d72f3ce Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 14 May 2015 08:50:43 -0700 Subject: [PATCH 02/11] Add option to auto mute microphone after lose face tracking --- interface/src/Application.cpp | 23 ++++++++++++++++++++++- interface/src/Application.h | 2 ++ interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1447d02db4..f74c11d7b0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -339,7 +339,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _domainConnectionRefusals(QList()), - _maxOctreePPS(maxOctreePacketsPerSecond.get()) + _maxOctreePPS(maxOctreePacketsPerSecond.get()), + _lastFaceTrackerUpdate(0) { setInstance(this); #ifdef Q_OS_WIN @@ -2409,7 +2410,27 @@ void Application::update(float deltaTime) { FaceTracker* tracker = getActiveFaceTracker(); if (tracker && !tracker->isMuted()) { tracker->update(deltaTime); + + // Auto-mute microphone after losing face tracking? + if (tracker->isTracking()) { + _lastFaceTrackerUpdate = usecTimestampNow(); + } else { + const quint64 MUTE_MICROPHONE_AFTER_USECS = 5000000; //5 secs + Menu* menu = Menu::getInstance(); + if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !menu->isOptionChecked(MenuOption::MuteAudio)) { + if (_lastFaceTrackerUpdate > 0 + && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { + menu->triggerOption(MenuOption::MuteAudio); + _lastFaceTrackerUpdate = 0; + } + } else { + _lastFaceTrackerUpdate = 0; + } + } + } else { + _lastFaceTrackerUpdate = 0; } + SixenseManager::getInstance().update(deltaTime); JoystickScriptingInterface::getInstance().update(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 83fc74aed4..2226c97b99 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -668,6 +668,8 @@ private: glm::uvec2 _renderResolution; int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS; + + quint64 _lastFaceTrackerUpdate; }; #endif // hifi_Application_h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0d7563f27a..bf9a4f34fa 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -407,6 +407,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::MuteFaceTracking, Qt::CTRL | Qt::SHIFT | Qt::Key_F, true, // DDE face tracking is on by default qApp, SLOT(toggleFaceTrackerMute())); + addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::AutoMuteAudio, 0, true); #endif auto avatarManager = DependencyManager::get(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 435df47487..12ec312a56 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -147,6 +147,7 @@ namespace MenuOption { const QString AudioScopeTwentyFrames = "Twenty"; const QString AudioStats = "Audio Stats"; const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; + const QString AutoMuteAudio = "Auto Mute Microphone"; const QString AvatarReceiveStats = "Show Receive Stats"; const QString BandwidthDetails = "Bandwidth Details"; const QString BinaryEyelidControl = "Binary Eyelid Control"; From cb02ef927738f4cad63e9d3afa5b8809f1f15701 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 15 May 2015 17:36:58 +0200 Subject: [PATCH 03/11] Remove warnings --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 3afd930ab0..bcbec4e67e 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -25,7 +25,6 @@ #include "EntityTreeRenderer.h" -const int FIXED_FONT_POINT_SIZE = 40; const float DPI = 30.47; const float METERS_TO_INCHES = 39.3701; @@ -161,7 +160,6 @@ void RenderableWebEntityItem::render(RenderArgs* args) { glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - float alpha = 1.0f; static const glm::vec2 texMin(0); static const glm::vec2 texMax(1); glm::vec2 topLeft(-halfDimensions.x, -halfDimensions.y); From 940363bf2e925d2a29b0abbf9f4465421d4a8068 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 15 May 2015 21:36:37 +0200 Subject: [PATCH 04/11] Fix activeRendernigThread check --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 20c93a7ae5..1e313254fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3079,7 +3079,7 @@ PickRay Application::computePickRay(float x, float y) const { if (isHMDMode()) { ApplicationOverlay::computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); } else { - if (activeRenderingThread) { + if (QThread::currentThread() == activeRenderingThread) { getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); } else { getViewFrustum()->computePickRay(x, y, result.origin, result.direction); From 75ddad7ec10a1dfd13b2d3ccf26fa03fe00f2bf5 Mon Sep 17 00:00:00 2001 From: Nex Pro Date: Sat, 16 May 2015 00:43:05 +0100 Subject: [PATCH 05/11] Added values for friction and restitution in the entity parameters. --- examples/example/games/planky.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index de8bbbb80b..00a4e7f61d 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -23,6 +23,8 @@ const GRAVITY = {x: 0, y: -2.8, z: 0}; const DENSITY = 2000; const DAMPING_FACTOR = 0.98; const ANGULAR_DAMPING_FACTOR = 0.8; +const FRICTION = 0.99; +const RESTITUTION = 0.0; const SPAWN_DISTANCE = 3; const BLOCK_YAW_OFFSET = 45; const BUTTON_DIMENSIONS = {width: 49, height: 49}; @@ -110,6 +112,8 @@ function resetBlocks() { rotation: Quat.multiply(layerRotation, offsetRot), collisionsWillMove: true, damping: DAMPING_FACTOR, + restitution: RESTITUTION, + friction: FRICTION, angularDamping: ANGULAR_DAMPING_FACTOR, gravity: GRAVITY, density: DENSITY From b6f1a1b89be33e4c285f8c968178f298706b2b12 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Sat, 16 May 2015 07:34:32 -0700 Subject: [PATCH 06/11] added check to airhockey script so entities that have never been created are not attempting to be deleted --- examples/example/games/airHockey.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js index ecef697b3e..74e00ed678 100644 --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -103,6 +103,8 @@ var spawnButton = Overlays.addOverlay("image", { + + var floor, edge1, edge2, edge3a, edge3b, edge4a, edge4b, light; var puck; var paddle1, paddle2; @@ -564,6 +566,13 @@ function scriptEnding() { Overlays.deleteOverlay(spawnButton); Overlays.deleteOverlay(deleteButton); + + //We only want to delete everything if we've spawned them first. + //Otherwise we'll throw an error- if we have edge1 we've spawned them all. + if(!edge1){ + return; + } + Entities.editEntity(edge1, { locked: false }); @@ -590,7 +599,6 @@ function scriptEnding() { }); - Entities.deleteEntity(edge1); Entities.deleteEntity(edge2); Entities.deleteEntity(edge3a); From 03a4e085732532fc5d14a88e6cc04c5abce120f6 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Sat, 16 May 2015 07:41:25 -0700 Subject: [PATCH 07/11] deleted unecsesary whitespace --- examples/example/games/airHockey.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js index 74e00ed678..c0640b8331 100644 --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -103,8 +103,6 @@ var spawnButton = Overlays.addOverlay("image", { - - var floor, edge1, edge2, edge3a, edge3b, edge4a, edge4b, light; var puck; var paddle1, paddle2; From 9d27108acbb0dede5bfc412e5eefb7ec7984e29e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 May 2015 13:29:13 +0200 Subject: [PATCH 08/11] Fix sourceUrl box in edit.js --- examples/html/entityProperties.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 0e3494bff8..a2ff71d010 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -284,7 +284,7 @@ var elModelOriginalTextures = document.getElementById("property-model-original-textures"); var elWebSections = document.querySelectorAll(".web-section"); - allSections.push(elModelSections); + allSections.push(elWebSections); var elWebSourceURL = document.getElementById("property-web-source-url"); var elTextSections = document.querySelectorAll(".text-section"); @@ -481,7 +481,7 @@ elModelTextures.value = properties.textures; elModelOriginalTextures.value = properties.originalTextures; } else if (properties.type == "Web") { - for (var i = 0; i < elTextSections.length; i++) { + for (var i = 0; i < elWebSections.length; i++) { elWebSections[i].style.display = 'block'; } From bb38b3eb3f8094b6e200c27ee7f7862971d835e3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 20 May 2015 09:11:21 -0700 Subject: [PATCH 09/11] Update default light cutoff to PI / 2 --- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityItemPropertiesDefaults.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index fd3d0e9361..61b25fd7de 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -64,7 +64,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(isSpotlight, false), CONSTRUCT_PROPERTY(intensity, 1.0f), CONSTRUCT_PROPERTY(exponent, 0.0f), - CONSTRUCT_PROPERTY(cutoff, PI), + CONSTRUCT_PROPERTY(cutoff, ENTITY_ITEM_DEFAULT_CUTOFF), CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED), CONSTRUCT_PROPERTY(textures, ""), CONSTRUCT_PROPERTY(animationSettings, ""), diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index b33e6de1ac..c3dea91daa 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -64,6 +64,8 @@ const float ENTITY_ITEM_DEFAULT_FRICTION = 0.5f; const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false; const bool ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE = false; +const float ENTITY_ITEM_DEFAULT_CUTOFF = PI / 2; + const QString ENTITY_ITEM_DEFAULT_NAME = QString(""); #endif // hifi_EntityItemPropertiesDefaults_h From 6f69ed2561009d3c099d90b680773781f453d245 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 20 May 2015 09:11:48 -0700 Subject: [PATCH 10/11] Fix calculated dimensions of spotlight The spotlights region of effect is the intersection of the spotlight with radius r, and the sphere of radius r --- examples/libraries/entitySelectionTool.js | 2 +- libraries/entities/src/LightEntityItem.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index f3ea18aef3..1790767bec 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1213,7 +1213,7 @@ SelectionDisplay = (function () { rotation: rotation, visible: true, }); - var distance = (properties.dimensions.z / 2) * Math.tan(properties.cutoff * (Math.PI / 180)); + var distance = (properties.dimensions.z / 2) * Math.sin(properties.cutoff * (Math.PI / 180)); Overlays.editOverlay(grabberSpotLightL, { position: EdgeNL, diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index a66cb56bd2..fa09c9bd60 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -46,7 +46,7 @@ void LightEntityItem::setDimensions(const glm::vec3& value) { // If we are a spotlight, treat the z value as our radius or length, and // recalculate the x/y dimensions to properly encapsulate the spotlight. const float length = value.z; - const float width = length * glm::tan(glm::radians(_cutoff)); + const float width = length * glm::sin(glm::radians(_cutoff)); _dimensions = glm::vec3(width, width, length); } else { float maxDimension = glm::max(value.x, value.y, value.z); @@ -73,7 +73,7 @@ void LightEntityItem::setIsSpotlight(bool value) { if (_isSpotlight) { const float length = _dimensions.z; - const float width = length * glm::tan(glm::radians(_cutoff)); + const float width = length * glm::sin(glm::radians(_cutoff)); _dimensions = glm::vec3(width, width, length); } else { float maxDimension = glm::max(_dimensions.x, _dimensions.y, _dimensions.z); @@ -89,7 +89,7 @@ void LightEntityItem::setCutoff(float value) { // If we are a spotlight, adjusting the cutoff will affect the area we encapsulate, // so update the dimensions to reflect this. const float length = _dimensions.z; - const float width = length * glm::tan(glm::radians(_cutoff)); + const float width = length * glm::sin(glm::radians(_cutoff)); _dimensions = glm::vec3(width, width, length); } } From c5b8dd51d8df9520cc1c12a608bb9cf360029961 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 20 May 2015 11:07:03 -0700 Subject: [PATCH 11/11] Fix https://app.asana.com/0/32622044445063/34195351184789 Handle collision events when we do other updates (and their entity scripts) rather than when we do the physic updates while the tree is locked. Given that, remove the check that kept sound from playing (or scripts from running) when we would have deadlocked, because now we don't. --- interface/src/Application.cpp | 7 ++++--- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 10 +--------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 37ee116f40..747b765ff7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2461,7 +2461,6 @@ void Application::update(float deltaTime) { if (_physicsEngine.hasOutgoingChanges()) { _entitySimulation.lock(); _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID()); - _entitySimulation.handleCollisionEvents(_physicsEngine.getCollisionEvents()); _entitySimulation.unlock(); _physicsEngine.dumpStatsIfNecessary(); } @@ -2469,9 +2468,11 @@ void Application::update(float deltaTime) { if (!_aboutToQuit) { PerformanceTimer perfTimer("entities"); - // NOTE: the _entities.update() call below will wait for lock + // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk deadlock.) + _entitySimulation.handleCollisionEvents(_physicsEngine.getCollisionEvents()); + // NOTE: the _entities.update() call below will wait for lock // and will simulate entity motion (the EntityTree has been given an EntitySimulation). - _entities.update(); // update the models... + _entities.update(); // update the models... } { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index bacd6eb56e..e8627e655a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1174,8 +1174,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons if (!_tree || _shuttingDown) { return; } - // Don't respond to small continuous contacts. It causes deadlocks when locking the entityTree. - // Note that any entity script is likely to Entities.getEntityProperties(), which locks the tree. + // Don't respond to small continuous contacts. const float COLLISION_MINUMUM_PENETRATION = 0.005; if ((collision.type != CONTACT_EVENT_TYPE_START) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) { return; @@ -1183,16 +1182,9 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons // See if we should play sounds EntityTree* entityTree = static_cast(_tree); - if (!entityTree->tryLockForRead()) { - // I don't know why this can happen, but if it does, - // the consequences are a deadlock, so bail. - qCDebug(entitiesrenderer) << "NOTICE: skipping collision type " << collision.type << " penetration " << glm::length(collision.penetration); - return; - } const QUuid& myNodeID = DependencyManager::get()->getSessionUUID(); playEntityCollisionSound(myNodeID, entityTree, idA, collision); playEntityCollisionSound(myNodeID, entityTree, idB, collision); - entityTree->unlock(); // And now the entity scripts QScriptValue entityScriptA = loadEntityScript(idA);