diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js index abacc05a9b..a703f379bc 100644 --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -392,6 +392,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 }); @@ -418,7 +425,6 @@ function scriptEnding() { }); - Entities.deleteEntity(edge1); Entities.deleteEntity(edge2); Entities.deleteEntity(edge3a); 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 diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 0879e0d01b..2385588fd5 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'; } diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 1cf9bf0e8f..d12c9dae3c 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1161,7 +1161,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/interface/src/Application.cpp b/interface/src/Application.cpp index 37ee116f40..6c660eb301 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 @@ -2413,7 +2414,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(); } @@ -2461,7 +2482,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 +2489,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/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 95877b92c4..ddd581fe53 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"; diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 30165624af..f37007894b 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); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c8b20e92e1..7bc253d00a 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); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 9d8a5ab6d2..f416fff744 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); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5f1d063b36..d5f866f045 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 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); } }