From 43c98b3f1e634f172bcc281f83774769f8546ddd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Sep 2016 14:42:53 -0700 Subject: [PATCH 001/126] attempt to avoid a very-still far-grab leaving something non-dynamic in bullet upon release. adjust position of grab-point sphere --- .../system/controllers/handControllerGrab.js | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 28488c9f3b..0f522c2c77 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -106,7 +106,7 @@ var MAX_EQUIP_HOTSPOT_RADIUS = 1.0; var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var NEAR_GRAB_RADIUS = 0.07; // radius used for palm vs object for near grabbing. +var NEAR_GRAB_RADIUS = 0.04; // radius used for palm vs object for near grabbing. var NEAR_GRAB_MAX_DISTANCE = 1.0; // you cannot grab objects that are this far away from your hand var NEAR_GRAB_PICK_RADIUS = 0.25; // radius used for search ray vs object for near grabbing. @@ -118,7 +118,7 @@ var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-g var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks -var GRAB_POINT_SPHERE_OFFSET = { x: 0.0, y: 0.2, z: 0.0 }; +var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: -0.04 }; var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS; var GRAB_POINT_SPHERE_COLOR = { red: 20, green: 90, blue: 238 }; var GRAB_POINT_SPHERE_ALPHA = 0.85; @@ -722,6 +722,7 @@ var equipHotspotBuddy = new EquipHotspotBuddy(); function MyController(hand) { this.hand = hand; this.autoUnequipCounter = 0; + this.grabPointIntersectsEntity = false; // handPosition is where the avatar's hand appears to be, in-world. this.getHandPosition = function () { @@ -738,6 +739,18 @@ function MyController(hand) { return MyAvatar.getLeftPalmRotation(); } }; + + this.getGrabPointSphereOffset = function() { + if (hand === RIGHT_HAND) { + return GRAB_POINT_SPHERE_OFFSET; + } + return { + x: GRAB_POINT_SPHERE_OFFSET.x * -1, + y: GRAB_POINT_SPHERE_OFFSET.y, + z: GRAB_POINT_SPHERE_OFFSET.z * -1 + }; + }; + // controllerLocation is where the controller would be, in-world. this.getControllerLocation = function (doOffset) { var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; @@ -747,7 +760,7 @@ function MyController(hand) { var position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position); // add to the real position so the grab-point is out in front of the hand, a bit if (doOffset) { - position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, GRAB_POINT_SPHERE_OFFSET)); + position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, this.getGrabPointSphereOffset())); } return {position: position, orientation: orientation}; @@ -866,7 +879,7 @@ function MyController(hand) { } if (!this.grabPointSphere) { this.grabPointSphere = Overlays.addOverlay("sphere", { - localPosition: GRAB_POINT_SPHERE_OFFSET, + localPosition: this.getGrabPointSphereOffset(), localRotation: { x: 0, y: 0, z: 0, w: 1 }, dimensions: GRAB_POINT_SPHERE_RADIUS, color: GRAB_POINT_SPHERE_COLOR, @@ -1465,6 +1478,16 @@ function MyController(hand) { return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE); }); + // before including any ray-picked entities, give a haptic pulse if the grab-point has hit something grabbable + if (grabbableEntities.length > 0) { + if (!this.grabPointIntersectsEntity) { + Controller.triggerHapticPulse(1, 20, this.hand); + this.grabPointIntersectsEntity = true; + } + } else { + this.grabPointIntersectsEntity = false; + } + if (rayPickInfo.entityID) { this.intersectionDistance = rayPickInfo.distance; if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) { @@ -1683,6 +1706,15 @@ function MyController(hand) { if (!this.triggerClicked) { this.callEntityMethodOnGrabbed("releaseGrab"); + + // if we distance hold something and keep it very still before releasing it, it ends up + // non-dynamic in bullet. If it's too still, give it a little bounce so it will fall. + var velocity = Entities.getEntityProperties(this.grabbedEntity, ["velocity"]).velocity; + if (Vec3.length(velocity) < 0.05) { // see EntityMotionState.cpp DYNAMIC_LINEAR_VELOCITY_THRESHOLD + velocity = { x: 0.0, y: 0.2, z:0.0 }; + Entities.editEntity(this.grabbedEntity, { velocity: velocity }); + } + this.setState(STATE_OFF, "trigger released"); return; } From 215fd4ddfdb943ae0456fa619061f59b6d032990 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Sep 2016 15:15:46 -0700 Subject: [PATCH 002/126] fix grab-point sphere for right hand --- scripts/system/controllers/handControllerGrab.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 0f522c2c77..1700bde25e 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -118,7 +118,7 @@ var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-g var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks -var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: -0.04 }; +var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 }; var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS; var GRAB_POINT_SPHERE_COLOR = { red: 20, green: 90, blue: 238 }; var GRAB_POINT_SPHERE_ALPHA = 0.85; @@ -747,7 +747,7 @@ function MyController(hand) { return { x: GRAB_POINT_SPHERE_OFFSET.x * -1, y: GRAB_POINT_SPHERE_OFFSET.y, - z: GRAB_POINT_SPHERE_OFFSET.z * -1 + z: GRAB_POINT_SPHERE_OFFSET.z }; }; @@ -1481,7 +1481,8 @@ function MyController(hand) { // before including any ray-picked entities, give a haptic pulse if the grab-point has hit something grabbable if (grabbableEntities.length > 0) { if (!this.grabPointIntersectsEntity) { - Controller.triggerHapticPulse(1, 20, this.hand); + // Controller.triggerHapticPulse(1, 20, this.hand); + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); this.grabPointIntersectsEntity = true; } } else { From 34e4b4ae1964a249b34b3c83580b03caecd1344d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Sep 2016 15:37:37 -0700 Subject: [PATCH 003/126] move haptic-pulse for when grab-point enters a grabbable entity to the right section of code --- .../system/controllers/handControllerGrab.js | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 1700bde25e..79331f0f3d 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1116,11 +1116,14 @@ function MyController(hand) { this.grabPointSphereOn(); - var candidateEntities = Entities.findEntities(this.getControllerLocation(true).position, MAX_EQUIP_HOTSPOT_RADIUS); + var controllerLocation = this.getControllerLocation(true); + var worldHandPosition = controllerLocation.position; + + var candidateEntities = Entities.findEntities(worldHandPosition, MAX_EQUIP_HOTSPOT_RADIUS); entityPropertiesCache.addEntities(candidateEntities); var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities); if (!this.waitForTriggerRelease) { - this.updateEquipHaptics(potentialEquipHotspot, this.getControllerLocation(true).position); + this.updateEquipHaptics(potentialEquipHotspot, worldHandPosition); } var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS); @@ -1128,6 +1131,20 @@ function MyController(hand) { if (potentialEquipHotspot) { equipHotspotBuddy.highlightHotspot(potentialEquipHotspot); } + + // when the grab-point enters a grabable entity, give a haptic pulse + candidateEntities = Entities.findEntities(worldHandPosition, NEAR_GRAB_RADIUS); + var grabbableEntities = candidateEntities.filter(function(entity) { + return _this.entityIsNearGrabbable(entity, worldHandPosition, NEAR_GRAB_MAX_DISTANCE); + }); + if (grabbableEntities.length > 0) { + if (!this.grabPointIntersectsEntity) { + Controller.triggerHapticPulse(1, 20, this.hand); + this.grabPointIntersectsEntity = true; + } + } else { + this.grabPointIntersectsEntity = false; + } }; this.clearEquipHaptics = function() { @@ -1478,17 +1495,6 @@ function MyController(hand) { return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE); }); - // before including any ray-picked entities, give a haptic pulse if the grab-point has hit something grabbable - if (grabbableEntities.length > 0) { - if (!this.grabPointIntersectsEntity) { - // Controller.triggerHapticPulse(1, 20, this.hand); - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.grabPointIntersectsEntity = true; - } - } else { - this.grabPointIntersectsEntity = false; - } - if (rayPickInfo.entityID) { this.intersectionDistance = rayPickInfo.distance; if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) { From 616b094111435c141cec9469f1e052fb55cc702f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Sep 2016 16:16:09 -0700 Subject: [PATCH 004/126] experimenting with position of grab sphere --- scripts/system/controllers/handControllerGrab.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 79331f0f3d..cc43a57a68 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -118,7 +118,9 @@ var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-g var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks -var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 }; +// var GRAB_POINT_SPHERE_OFFSET = { x: 0, y: 0.2, z: 0 }; +// var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 }; +var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.32, z: 0.04 }; var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS; var GRAB_POINT_SPHERE_COLOR = { red: 20, green: 90, blue: 238 }; var GRAB_POINT_SPHERE_ALPHA = 0.85; From 624cc655ddbf1af5aa50cb8e32d2efc5ca271ef1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 7 Sep 2016 13:24:53 -0700 Subject: [PATCH 005/126] disable code that backs-up in time to pick release velocity --- interface/src/avatar/AvatarActionHold.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 51171b9c6b..ce4455d921 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -244,14 +244,18 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { // 3 -- ignore i of 0 1 2 // 4 -- ignore i of 1 2 3 // 5 -- ignore i of 2 3 4 - if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || - (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || - (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) { - continue; - } + + // if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || + // (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || + // (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) { + // continue; + // } + measuredLinearVelocity += _measuredLinearVelocities[i]; } - measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames - 3); // 3 because of the 3 we skipped, above + measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames + // - 3 // 3 because of the 3 we skipped, above + ); if (_kinematicSetVelocity) { rigidBody->setLinearVelocity(glmToBullet(measuredLinearVelocity)); From b45181ea9210dcad5ba9e4295aae833b0ae4d4e5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 7 Sep 2016 13:32:26 -0700 Subject: [PATCH 006/126] don't back up pick-ray from hand --- scripts/system/controllers/handControllerGrab.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index cc43a57a68..6f34ec4294 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1202,16 +1202,12 @@ function MyController(hand) { var directionNormalized = Vec3.normalize(pickRay.direction); var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var pickRayBacked = { - origin: Vec3.subtract(pickRay.origin, directionBacked), - direction: pickRay.direction - }; var intersection; if (USE_BLACKLIST === true && blacklist.length !== 0) { - intersection = findRayIntersection(pickRayBacked, true, [], blacklist); + intersection = findRayIntersection(pickRay, true, [], blacklist); } else { - intersection = findRayIntersection(pickRayBacked, true); + intersection = findRayIntersection(pickRay, true); } if (intersection.intersects) { From 746d0cd91ce2c0b145ee51700d31f0d3081a2713 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 7 Sep 2016 16:10:37 -0700 Subject: [PATCH 007/126] get various hand lasers to all line up with grab-point sphere --- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 22 ++++-- .../system/controllers/handControllerGrab.js | 78 +++++++------------ .../controllers/handControllerPointer.js | 12 ++- scripts/system/libraries/controllers.js | 46 +++++++++++ scripts/system/mod.js | 12 ++- 5 files changed, 99 insertions(+), 71 deletions(-) create mode 100644 scripts/system/libraries/controllers.js diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 01f607b0ed..28b19ee9e0 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -277,27 +277,37 @@ void HmdDisplayPlugin::updateFrameData() { continue; } - const auto& laserDirection = handLaser.direction; - auto model = _presentHandPoses[i]; - auto castDirection = glm::quat_cast(model) * laserDirection; + const vec3& laserDirection = handLaser.direction; + mat4 model = _presentHandPoses[i]; + vec3 castStart = vec3(model[3]); + vec3 castDirection = glm::quat_cast(model) * laserDirection; if (glm::abs(glm::length2(castDirection) - 1.0f) > EPSILON) { castDirection = glm::normalize(castDirection); castDirection = glm::inverse(_presentUiModelTransform.getRotation()) * castDirection; } + // this offset needs to match GRAB_POINT_SPHERE_OFFSET in scripts/system/libraries/controllers.js + static const vec3 GRAB_POINT_SPHERE_OFFSET = vec3(0.1f, 0.04f, -0.32f); + vec3 grabPointOffset = GRAB_POINT_SPHERE_OFFSET; + if (i == 0) { + grabPointOffset.x *= -1.0f; // this changes between left and right hands + } + castStart += glm::quat_cast(model) * grabPointOffset; + // FIXME fetch the actual UI radius from... somewhere? float uiRadius = 1.0f; // Find the intersection of the laser with he UI and use it to scale the model matrix float distance; - if (!glm::intersectRaySphere(vec3(_presentHandPoses[i][3]), castDirection, _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { + if (!glm::intersectRaySphere(castStart, castDirection, + _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { continue; } - _presentHandLaserPoints[i].first = vec3(_presentHandPoses[i][3]); + _presentHandLaserPoints[i].first = castStart; _presentHandLaserPoints[i].second = _presentHandLaserPoints[i].first + (castDirection * distance); - vec3 intersectionPosition = vec3(_presentHandPoses[i][3]) + (castDirection * distance) - _presentUiModelTransform.getTranslation(); + vec3 intersectionPosition = castStart + (castDirection * distance) - _presentUiModelTransform.getTranslation(); intersectionPosition = glm::inverse(_presentUiModelTransform.getRotation()) * intersectionPosition; // Take the interesection normal and convert it to a texture coordinate diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 6f34ec4294..01be03c14a 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -11,12 +11,13 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4 */ +/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation */ (function() { // BEGIN LOCAL_SCOPE Script.include("/~/system/libraries/utils.js"); Script.include("/~/system/libraries/Xform.js"); +Script.include("/~/system/libraries/controllers.js"); // // add lines where the hand ray picking is happening @@ -110,17 +111,12 @@ var NEAR_GRAB_RADIUS = 0.04; // radius used for palm vs object for near grabbing var NEAR_GRAB_MAX_DISTANCE = 1.0; // you cannot grab objects that are this far away from your hand var NEAR_GRAB_PICK_RADIUS = 0.25; // radius used for search ray vs object for near grabbing. - -var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed // if an equipped item is "adjusted" to be too far from the hand it's in, it will be unequipped. var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks -// var GRAB_POINT_SPHERE_OFFSET = { x: 0, y: 0.2, z: 0 }; -// var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 }; -var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.32, z: 0.04 }; var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS; var GRAB_POINT_SPHERE_COLOR = { red: 20, green: 90, blue: 238 }; var GRAB_POINT_SPHERE_ALPHA = 0.85; @@ -742,30 +738,8 @@ function MyController(hand) { } }; - this.getGrabPointSphereOffset = function() { - if (hand === RIGHT_HAND) { - return GRAB_POINT_SPHERE_OFFSET; - } - return { - x: GRAB_POINT_SPHERE_OFFSET.x * -1, - y: GRAB_POINT_SPHERE_OFFSET.y, - z: GRAB_POINT_SPHERE_OFFSET.z - }; - }; - - // controllerLocation is where the controller would be, in-world. - this.getControllerLocation = function (doOffset) { - var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var pose = Controller.getPoseValue(standardControllerValue); - - var orientation = Quat.multiply(MyAvatar.orientation, pose.rotation); - var position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position); - // add to the real position so the grab-point is out in front of the hand, a bit - if (doOffset) { - position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, this.getGrabPointSphereOffset())); - } - - return {position: position, orientation: orientation}; + this.handToController = function() { + return (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; }; this.actionID = null; // action this script created... @@ -881,7 +855,7 @@ function MyController(hand) { } if (!this.grabPointSphere) { this.grabPointSphere = Overlays.addOverlay("sphere", { - localPosition: this.getGrabPointSphereOffset(), + localPosition: getGrabPointSphereOffset(this.handToController()), localRotation: { x: 0, y: 0, z: 0, w: 1 }, dimensions: GRAB_POINT_SPHERE_RADIUS, color: GRAB_POINT_SPHERE_COLOR, @@ -1109,7 +1083,7 @@ function MyController(hand) { } if (!this.waitForTriggerRelease && this.triggerSmoothedSqueezed()) { this.lastPickTime = 0; - this.startingHandRotation = this.getControllerLocation(true).orientation; + this.startingHandRotation = getControllerWorldLocation(this.handToController(), true).orientation; if (this.triggerSmoothedSqueezed()) { this.setState(STATE_SEARCHING, "trigger squeeze detected"); return; @@ -1118,7 +1092,7 @@ function MyController(hand) { this.grabPointSphereOn(); - var controllerLocation = this.getControllerLocation(true); + var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldHandPosition = controllerLocation.position; var candidateEntities = Entities.findEntities(worldHandPosition, MAX_EQUIP_HOTSPOT_RADIUS); @@ -1176,7 +1150,7 @@ function MyController(hand) { // @returns {object} returns object with two keys entityID and distance // this.calcRayPickInfo = function(hand) { - var controllerLocation = this.getControllerLocation(true); + var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldHandPosition = controllerLocation.position; var worldHandRotation = controllerLocation.orientation; @@ -1200,9 +1174,6 @@ function MyController(hand) { } this.lastPickTime = now; - var directionNormalized = Vec3.normalize(pickRay.direction); - var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var intersection; if (USE_BLACKLIST === true && blacklist.length !== 0) { intersection = findRayIntersection(pickRay, true, [], blacklist); @@ -1420,7 +1391,8 @@ function MyController(hand) { return _this.collectEquipHotspots(entityID); })).filter(function(hotspot) { return (_this.hotspotIsEquippable(hotspot) && - Vec3.distance(hotspot.worldPosition, _this.getControllerLocation(true).position) < hotspot.radius + distance); + Vec3.distance(hotspot.worldPosition, getControllerWorldLocation(_this.handToController(), true).position) < + hotspot.radius + distance); }); return equippableHotspots; }; @@ -1431,8 +1403,9 @@ function MyController(hand) { if (equippableHotspots.length > 0) { // sort by distance equippableHotspots.sort(function(a, b) { - var aDistance = Vec3.distance(a.worldPosition, this.getControllerLocation(true).position); - var bDistance = Vec3.distance(b.worldPosition, this.getControllerLocation(true).position); + var handControllerLocation = getControllerWorldLocation(this.handToController(), true); + var aDistance = Vec3.distance(a.worldPosition, handControllerLocation.position); + var bDistance = Vec3.distance(b.worldPosition, handControllerLocation.position); return aDistance - bDistance; }); return equippableHotspots[0]; @@ -1467,7 +1440,7 @@ function MyController(hand) { return; } - var handPosition = this.getControllerLocation(true).position; + var handPosition = getControllerWorldLocation(this.handToController(), true).position; var rayPickInfo = this.calcRayPickInfo(this.hand); @@ -1652,7 +1625,7 @@ function MyController(hand) { this.clearEquipHaptics(); this.grabPointSphereOff(); - var worldControllerPosition = this.getControllerLocation(true).position; + var worldControllerPosition = getControllerWorldLocation(this.handToController(), true).position; // transform the position into room space var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); @@ -1727,7 +1700,7 @@ function MyController(hand) { this.heartBeat(this.grabbedEntity); - var controllerLocation = this.getControllerLocation(true); + var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; @@ -1864,7 +1837,7 @@ function MyController(hand) { }; this.dropGestureProcess = function(deltaTime) { - var worldHandRotation = this.getControllerLocation(true).orientation; + var worldHandRotation = getControllerWorldLocation(this.handToController(), true).orientation; var localHandUpAxis = this.hand === RIGHT_HAND ? { x: 1, y: 0, @@ -1942,7 +1915,7 @@ function MyController(hand) { var handRotation; var handPosition; if (this.ignoreIK) { - var controllerLocation = this.getControllerLocation(false); + var controllerLocation = getControllerWorldLocation(this.handToController(), false); handRotation = controllerLocation.orientation; handPosition = controllerLocation.position; } else { @@ -2122,7 +2095,7 @@ function MyController(hand) { if (props.parentID == MyAvatar.sessionUUID) { var handPosition; if (this.ignoreIK) { - handPosition = this.getControllerLocation(false).position; + handPosition = getControllerWorldLocation(this.handToController(), false).position; } else { handPosition = this.getHandPosition(); } @@ -2238,8 +2211,8 @@ function MyController(hand) { } var pickRay = { - origin: this.getControllerLocation().position, - direction: Quat.getUp(this.getControllerLocation().orientation) + origin: getControllerWorldLocation(this.handToController(), false).position, + direction: Quat.getUp(getControllerWorldLocation(this.handToController(), false).orientation) }; var now = Date.now(); @@ -2268,7 +2241,8 @@ function MyController(hand) { this.entityTouchingEnter = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true)); + var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { var pointerEvent = { type: "Press", @@ -2293,7 +2267,8 @@ function MyController(hand) { this.entityTouchingExit = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true)); + var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { var pointerEvent; if (this.deadspotExpired) { @@ -2331,7 +2306,8 @@ function MyController(hand) { } // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true)); + var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { if (Entities.keyboardFocusEntity != this.grabbedEntity) { diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 6b62674be5..ce98ed6d8e 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -20,6 +20,7 @@ // When partially squeezing over a HUD element, a laser or the reticle is shown where the active hand // controller beam intersects the HUD. +Script.include("/~/system/libraries/controllers.js"); // UTILITIES ------------- // @@ -203,16 +204,13 @@ function overlayFromWorldPoint(point) { } function activeHudPoint2d(activeHand) { // if controller is valid, update reticle position and answer 2d point. Otherwise falsey. - var controllerPose = Controller.getPoseValue(activeHand); - // Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...) + var controllerPose = getControllerWorldLocation(activeHand, true); if (!controllerPose.valid) { return; // Controller is cradled. } - var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), - MyAvatar.position); - // This gets point direction right, but if you want general quaternion it would be more complicated: - var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation)); - + var controllerPosition = controllerPose.position; + var controllerDirection = Quat.getUp(controllerPose.rotation); + var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection); if (!hudPoint3d) { if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here diff --git a/scripts/system/libraries/controllers.js b/scripts/system/libraries/controllers.js new file mode 100644 index 0000000000..a1318ca47c --- /dev/null +++ b/scripts/system/libraries/controllers.js @@ -0,0 +1,46 @@ +// handControllerGrab.js +// +// Created by Seth Alves on 2016-9-7 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +/* global MyAvatar, Vec3, Controller, Quat */ + + +// var GRAB_POINT_SPHERE_OFFSET = { x: 0, y: 0.2, z: 0 }; +// var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 }; + +// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.32, z: 0.04 }; + +getGrabPointSphereOffset = function(handController) { + if (handController === Controller.Standard.RightHand) { + return GRAB_POINT_SPHERE_OFFSET; + } + return { + x: GRAB_POINT_SPHERE_OFFSET.x * -1, + y: GRAB_POINT_SPHERE_OFFSET.y, + z: GRAB_POINT_SPHERE_OFFSET.z + }; +}; + +// controllerLocation is where the controller would be, in-world. +getControllerWorldLocation = function (handController, doOffset) { + var orientation; + var position; + var pose = Controller.getPoseValue(handController); + if (pose.valid) { + orientation = Quat.multiply(MyAvatar.orientation, pose.rotation); + position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position); + // add to the real position so the grab-point is out in front of the hand, a bit + if (doOffset) { + position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, getGrabPointSphereOffset(handController))); + } + } + return {position: position, + translation: position, + orientation: orientation, + rotation: orientation, + valid: pose.valid}; +}; diff --git a/scripts/system/mod.js b/scripts/system/mod.js index b2c9785539..4db1576168 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -10,6 +10,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* global Toolbars, Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */ + (function() { // BEGIN LOCAL_SCOPE @@ -144,7 +146,7 @@ AvatarList.avatarRemovedEvent.connect(function(avatarID){ function handleSelectedOverlay(clickedOverlay) { // see this is one of our mod overlays - var modOverlayKeys = Object.keys(modOverlays) + var modOverlayKeys = Object.keys(modOverlays); for (var i = 0; i < modOverlayKeys.length; ++i) { var avatarID = modOverlayKeys[i]; var modOverlay = modOverlays[avatarID]; @@ -187,13 +189,9 @@ Controller.mousePressEvent.connect(function(event){ var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); function controllerComputePickRay(hand) { - var controllerPose = Controller.getPoseValue(hand); + var controllerPose = getControllerWorldLocation(hand, true); if (controllerPose.valid) { - var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), - MyAvatar.position); - // This gets point direction right, but if you want general quaternion it would be more complicated: - var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation)); - return { origin: controllerPosition, direction: controllerDirection }; + return { origin: controllerPose.position, direction: controllerPose.orientation }; } } From 9c96ffc9cb42ff42274b29f7687f81878ccc8309 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 7 Sep 2016 16:31:02 -0700 Subject: [PATCH 008/126] don't show grab-point spheres if controller poses aren't valid --- .../system/controllers/handControllerGrab.js | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 01be03c14a..588f5f95b6 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -11,7 +11,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation */ +/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset */ (function() { // BEGIN LOCAL_SCOPE @@ -1090,11 +1090,16 @@ function MyController(hand) { } } - this.grabPointSphereOn(); var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldHandPosition = controllerLocation.position; + if (controllerLocation.valid) { + this.grabPointSphereOn(); + } else { + this.grabPointSphereOff(); + } + var candidateEntities = Entities.findEntities(worldHandPosition, MAX_EQUIP_HOTSPOT_RADIUS); entityPropertiesCache.addEntities(candidateEntities); var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities); @@ -1431,8 +1436,6 @@ function MyController(hand) { this.isInitialGrab = false; this.shouldResetParentOnRelease = false; - this.grabPointSphereOn(); - this.checkForStrayChildren(); if (this.triggerSmoothedReleased()) { @@ -1440,7 +1443,14 @@ function MyController(hand) { return; } - var handPosition = getControllerWorldLocation(this.handToController(), true).position; + var controllerLocation = getControllerWorldLocation(this.handToController(), true); + var handPosition = controllerLocation.position; + + if (controllerLocation.valid) { + this.grabPointSphereOn(); + } else { + this.grabPointSphereOff(); + } var rayPickInfo = this.calcRayPickInfo(this.hand); From 9e99cc1f7879156d51af33f759be3170c1303499 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 8 Sep 2016 07:35:52 -0700 Subject: [PATCH 009/126] fix mod.js --- scripts/system/libraries/controllers.js | 2 +- scripts/system/mod.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/system/libraries/controllers.js b/scripts/system/libraries/controllers.js index a1318ca47c..9bae46380e 100644 --- a/scripts/system/libraries/controllers.js +++ b/scripts/system/libraries/controllers.js @@ -25,7 +25,7 @@ getGrabPointSphereOffset = function(handController) { }; }; -// controllerLocation is where the controller would be, in-world. +// controllerWorldLocation is where the controller would be, in-world, with an added offset getControllerWorldLocation = function (handController, doOffset) { var orientation; var position; diff --git a/scripts/system/mod.js b/scripts/system/mod.js index 4db1576168..1a7b3b401e 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -15,6 +15,8 @@ (function() { // BEGIN LOCAL_SCOPE +Script.include("/~/system/libraries/controllers.js"); + // grab the toolbar var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); From d4faf69beb9536bacb62de23b1d3012447c7e85e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 8 Sep 2016 15:42:42 -0700 Subject: [PATCH 010/126] don't cripple interface with log-spam --- libraries/physics/src/EntityMotionState.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b70927d501..951728c4da 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "BulletUtil.h" #include "EntityMotionState.h" @@ -230,11 +231,17 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { bool positionSuccess; _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); if (!positionSuccess) { + static QString repeatedMessage = + LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " + "setPosition failed.*"); qDebug() << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID(); } bool orientationSuccess; _entity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); if (!orientationSuccess) { + static QString repeatedMessage = + LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " + "setOrientation failed.*"); qDebug() << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID(); } _entity->setVelocity(getBodyLinearVelocity()); From 0f98c51d89416fae07964a5f276f681016476f0e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 8 Sep 2016 16:13:22 -0700 Subject: [PATCH 011/126] distance-grabbed things collide with static entities --- .../system/controllers/handControllerGrab.js | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 588f5f95b6..a989b257c1 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1653,7 +1653,8 @@ function MyController(hand) { this.grabRadius = Vec3.distance(this.currentObjectPosition, worldControllerPosition); this.grabRadialVelocity = 0.0; - // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + // compute a constant based on the initial conditions which we use below to exagerate hand motion + // onto the held object this.radiusScalar = Math.log(this.grabRadius + 1.0); if (this.radiusScalar < 1.0) { this.radiusScalar = 1.0; @@ -1679,7 +1680,7 @@ function MyController(hand) { this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); if (this.actionID !== null) { - this.activateEntity(this.grabbedEntity, grabbedProperties, false); + this.activateEntity(this.grabbedEntity, grabbedProperties, false, true); this.callEntityMethodOnGrabbed("startDistanceGrab"); } @@ -1709,7 +1710,6 @@ function MyController(hand) { this.heartBeat(this.grabbedEntity); - var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; @@ -1913,7 +1913,7 @@ function MyController(hand) { } var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties, false); + this.activateEntity(this.grabbedEntity, grabbedProperties, false, false); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (FORCE_IGNORE_IK) { @@ -2422,7 +2422,7 @@ function MyController(hand) { this.deactivateEntity(entityID, false); }; - this.activateEntity = function(entityID, grabbedProperties, wasLoaded) { + this.activateEntity = function(entityID, grabbedProperties, wasLoaded, collideWithStatic) { this.autoUnequipCounter = 0; if (this.entityActivated) { @@ -2463,15 +2463,10 @@ function MyController(hand) { data.parentJointIndex = grabbedProperties.parentJointIndex; var whileHeldProperties = { - gravity: { - x: 0, - y: 0, - z: 0 - }, - // bummer, it isn't easy to do bitwise collisionMask operations like this: - // "collisionMask": COLLISION_MASK_WHILE_GRABBED | grabbedProperties.collisionMask - // when using string values - "collidesWith": COLLIDES_WITH_WHILE_GRABBED + gravity: { x: 0, y: 0, z: 0 }, + "collidesWith": collideWithStatic ? + COLLIDES_WITH_WHILE_GRABBED + ",static" : + COLLIDES_WITH_WHILE_GRABBED }; Entities.editEntity(entityID, whileHeldProperties); } else if (data.refCount > 1) { @@ -2480,7 +2475,7 @@ function MyController(hand) { // deactivate it before grabbing. this.resetAbandonedGrab(entityID); grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - return this.activateEntity(entityID, grabbedProperties, wasLoaded); + return this.activateEntity(entityID, grabbedProperties, wasLoaded, false); } this.isInitialGrab = false; From ecb06699721b644e44659558ebe4d006ea0db16a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 8 Sep 2016 17:02:29 -0700 Subject: [PATCH 012/126] try to keep far grab from getting stuck if the entity is brought very near to the grab-point --- scripts/system/controllers/handControllerGrab.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index a989b257c1..178e20a9cf 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1756,7 +1756,13 @@ function MyController(hand) { var RADIAL_GRAB_AMPLIFIER = 10.0; if (Math.abs(this.grabRadialVelocity) > 0.0) { this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); + this.grabRadius * RADIAL_GRAB_AMPLIFIER); + } + + // don't let grabRadius go all the way to zero, because it can't come back from that + var MINIMUM_GRAB_RADIUS = 0.1; + if (this.grabRadius < MINIMUM_GRAB_RADIUS) { + this.grabRadius = MINIMUM_GRAB_RADIUS; } var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); From 6ccf86e3e9d41b516d76b82e5ee307b6eb0ebd9e Mon Sep 17 00:00:00 2001 From: Marko Kudjerski Date: Tue, 13 Sep 2016 11:10:36 -0700 Subject: [PATCH 013/126] remove qtaudio_windows.dll on Windows before installing the new version --- cmake/templates/NSIS.template.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 65e801d321..a80367cee1 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -600,6 +600,9 @@ Section "-Core installation" Delete "$INSTDIR\version" Delete "$INSTDIR\xinput1_3.dll" + ;Delete old Qt files + Delete "$INSTDIR\audio\qtaudio_windows.dll" + ; Delete old desktop shortcuts before they were renamed during Sandbox rename Delete "$DESKTOP\@PRE_SANDBOX_INTERFACE_SHORTCUT_NAME@.lnk" Delete "$DESKTOP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk" From 724df38df0ffb6140c80de04f2aec4ef1fa67594 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 13 Sep 2016 16:11:06 -0700 Subject: [PATCH 014/126] Optimize the audio pipeline. Use float mixBuffer and apply reverb at 24khz --- libraries/audio-client/src/AudioClient.cpp | 81 +++++++++------------- libraries/audio-client/src/AudioClient.h | 4 +- 2 files changed, 35 insertions(+), 50 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index f96171af37..c681069516 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -683,8 +683,8 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { void AudioClient::configureReverb() { ReverbParameters p; - p.sampleRate = _outputFormat.sampleRate(); + p.sampleRate = AudioConstants::SAMPLE_RATE; p.bandwidth = _reverbOptions->getBandwidth(); p.preDelay = _reverbOptions->getPreDelay(); p.lateDelay = _reverbOptions->getLateDelay(); @@ -710,6 +710,7 @@ void AudioClient::configureReverb() { _listenerReverb.setParameters(&p); // used only for adding self-reverb to loopback audio + p.sampleRate = _outputFormat.sampleRate(); p.wetDryMix = 100.0f; p.preDelay = 0.0f; p.earlyGain = -96.0f; // disable ER @@ -958,12 +959,9 @@ void AudioClient::handleRecordedAudioInput(const QByteArray& audio) { emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, audioTransform, PacketType::MicrophoneAudioWithEcho, _selectedCodecName); } -void AudioClient::mixLocalAudioInjectors(int16_t* inputBuffer) { +void AudioClient::mixLocalAudioInjectors(float* mixBuffer) { - memset(_hrtfBuffer, 0, sizeof(_hrtfBuffer)); QVector injectorsToRemove; - static const float INT16_TO_FLOAT_SCALE_FACTOR = 1/32768.0f; - bool injectorsHaveData = false; // lock the injector vector @@ -972,9 +970,7 @@ void AudioClient::mixLocalAudioInjectors(int16_t* inputBuffer) { for (AudioInjector* injector : getActiveLocalAudioInjectors()) { if (injector->getLocalBuffer()) { - qint64 samplesToRead = injector->isStereo() ? - AudioConstants::NETWORK_FRAME_BYTES_STEREO : - AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL; + qint64 samplesToRead = injector->isStereo() ? AudioConstants::NETWORK_FRAME_BYTES_STEREO : AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL; // get one frame from the injector (mono or stereo) memset(_scratchBuffer, 0, sizeof(_scratchBuffer)); @@ -982,9 +978,11 @@ void AudioClient::mixLocalAudioInjectors(int16_t* inputBuffer) { injectorsHaveData = true; - if (injector->isStereo() ) { - for(int i=0; iisStereo()) { + + // stereo gets directly mixed into mixBuffer + for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; i++) { + mixBuffer[i] += (float)_scratchBuffer[i] * (1/32768.0f); } } else { @@ -995,7 +993,8 @@ void AudioClient::mixLocalAudioInjectors(int16_t* inputBuffer) { float gain = gainForSource(distance, injector->getVolume()); float azimuth = azimuthForSource(relativePosition); - injector->getLocalHRTF().render(_scratchBuffer, _hrtfBuffer, 1, azimuth, distance, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + // mono gets spatialized into mixBuffer + injector->getLocalHRTF().render(_scratchBuffer, mixBuffer, 1, azimuth, distance, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); } } else { @@ -1013,56 +1012,42 @@ void AudioClient::mixLocalAudioInjectors(int16_t* inputBuffer) { } } - if(injectorsHaveData) { - - // mix network into the hrtfBuffer - for(int i=0; i(outputBuffer.data()); - QByteArray decodedBufferCopy = decodedBuffer; + const int16_t* decodedSamples = reinterpret_cast(decodedBuffer.data()); assert(decodedBuffer.size() == AudioConstants::NETWORK_FRAME_BYTES_STEREO); - - if(getActiveLocalAudioInjectors().size() > 0) { - mixLocalAudioInjectors((int16_t*)decodedBufferCopy.data()); - decodedSamples = reinterpret_cast(decodedBufferCopy.data()); - } else { - decodedSamples = reinterpret_cast(decodedBuffer.data()); + + outputBuffer.resize(_outputFrameSize * sizeof(int16_t)); + int16_t* outputSamples = reinterpret_cast(outputBuffer.data()); + + // convert network audio to float + for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; i++) { + _mixBuffer[i] = (float)decodedSamples[i] * (1/32768.0f); + } + + // mix in active injectors + if (getActiveLocalAudioInjectors().size() > 0) { + mixLocalAudioInjectors(_mixBuffer); } - // copy the packet from the RB to the output - possibleResampling(_networkToOutputResampler, decodedSamples, outputSamples, - numDecodecSamples, numDeviceOutputSamples, - _desiredOutputFormat, _outputFormat); - - // apply stereo reverb at the listener, to the received audio + // apply stereo reverb bool hasReverb = _reverb || _receivedAudioStream.hasReverb(); if (hasReverb) { - assert(_outputFormat.channelCount() == 2); updateReverbOptions(); - _listenerReverb.render(outputSamples, outputSamples, numDeviceOutputSamples/2); + _listenerReverb.render(_mixBuffer, _mixBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); } + + // apply peak limiter + _audioLimiter.render(_mixBuffer, _scratchBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + + // resample to output sample rate + _networkToOutputResampler->render(_scratchBuffer, outputSamples, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); } void AudioClient::sendMuteEnvironmentPacket() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index ba6b98e1bd..53adba4a0d 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -227,7 +227,7 @@ protected: private: void outputFormatChanged(); - void mixLocalAudioInjectors(int16_t* inputBuffer); + void mixLocalAudioInjectors(float* mixBuffer); float azimuthForSource(const glm::vec3& relativePosition); float gainForSource(float distance, float volume); @@ -309,7 +309,7 @@ private: AudioSRC* _networkToOutputResampler; // for local hrtf-ing - float _hrtfBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; + float _mixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; int16_t _scratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; AudioLimiter _audioLimiter; From 3a41b285a0d1bc715a216a309e02366771e21d31 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 13 Sep 2016 17:21:48 -0700 Subject: [PATCH 015/126] Fix local audio injectors, that got disabled somehow --- libraries/audio/src/AudioInjector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 5fc07adb8d..c6368259c0 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -26,7 +26,7 @@ #include "SoundCache.h" #include "AudioSRC.h" -//int audioInjectorPtrMetaTypeId = qRegisterMetaType(); +int audioInjectorPtrMetaTypeId = qRegisterMetaType(); AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); From f1455ab1576e0db659621bf9da5624373b8e5e54 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 13 Sep 2016 20:06:44 -0700 Subject: [PATCH 016/126] Remove unneeded buffers --- libraries/audio-client/src/AudioClient.cpp | 3 --- libraries/audio-client/src/AudioClient.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index c681069516..4000a048ca 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -146,9 +146,6 @@ AudioClient::AudioClient() : _positionGetter(DEFAULT_POSITION_GETTER), _orientationGetter(DEFAULT_ORIENTATION_GETTER) { - // clear the array of locally injected samples - memset(_localProceduralSamples, 0, AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL); - connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &AudioClient::processReceivedSamples, Qt::DirectConnection); connect(this, &AudioClient::changeDevice, this, [=](const QAudioDeviceInfo& outputDeviceInfo) { switchOutputToAudioDevice(outputDeviceInfo); }); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 53adba4a0d..4a75b38bbb 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -259,12 +259,10 @@ private: QAudioFormat _inputFormat; QIODevice* _inputDevice; int _numInputCallbackBytes; - int16_t _localProceduralSamples[AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL]; QAudioOutput* _audioOutput; QAudioFormat _desiredOutputFormat; QAudioFormat _outputFormat; int _outputFrameSize; - int16_t _outputProcessingBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; int _numOutputCallbackBytes; QAudioOutput* _loopbackAudioOutput; QIODevice* _loopbackOutputDevice; From ed9061040a82054b13e02e54e1b9447a944df62f Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 13 Sep 2016 20:16:23 -0700 Subject: [PATCH 017/126] Better Android settings --- libraries/audio-client/src/AudioClient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 4000a048ca..b572664390 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -371,7 +371,8 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, adjustedAudioFormat = desiredAudioFormat; #ifdef Q_OS_ANDROID - adjustedAudioFormat.setSampleRate(44100); + // FIXME: query the native sample rate of the device? + adjustedAudioFormat.setSampleRate(48000); #else // From 27d24eb79b1b41ab2b5398a875a93e236f3f77ea Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 13 Sep 2016 20:56:36 -0700 Subject: [PATCH 018/126] Fix compiler warning --- libraries/audio-client/src/AudioClient.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index b572664390..a6b0e28a76 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -960,7 +960,6 @@ void AudioClient::handleRecordedAudioInput(const QByteArray& audio) { void AudioClient::mixLocalAudioInjectors(float* mixBuffer) { QVector injectorsToRemove; - bool injectorsHaveData = false; // lock the injector vector Lock lock(_injectorsMutex); @@ -974,8 +973,6 @@ void AudioClient::mixLocalAudioInjectors(float* mixBuffer) { memset(_scratchBuffer, 0, sizeof(_scratchBuffer)); if (0 < injector->getLocalBuffer()->readData((char*)_scratchBuffer, samplesToRead)) { - injectorsHaveData = true; - if (injector->isStereo()) { // stereo gets directly mixed into mixBuffer From c555e369c851121fc27e403263cd8a1c33a082eb Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 14 Sep 2016 06:37:09 -0700 Subject: [PATCH 019/126] Handle the case when resampling is not needed --- libraries/audio-client/src/AudioClient.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a6b0e28a76..8ce442b3ca 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1038,11 +1038,17 @@ void AudioClient::processReceivedSamples(const QByteArray& decodedBuffer, QByteA _listenerReverb.render(_mixBuffer, _mixBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); } - // apply peak limiter - _audioLimiter.render(_mixBuffer, _scratchBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + if (_networkToOutputResampler) { - // resample to output sample rate - _networkToOutputResampler->render(_scratchBuffer, outputSamples, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + // resample to output sample rate + _audioLimiter.render(_mixBuffer, _scratchBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + _networkToOutputResampler->render(_scratchBuffer, outputSamples, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + + } else { + + // no resampling needed + _audioLimiter.render(_mixBuffer, outputSamples, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + } } void AudioClient::sendMuteEnvironmentPacket() { From 96313a421c8ca91664300f22eda9644617062003 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 14 Sep 2016 08:22:18 -0700 Subject: [PATCH 020/126] Cleanup the confusion of using null-resampler for channel conversion --- libraries/audio-client/src/AudioClient.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 8ce442b3ca..1c4cde8204 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -823,15 +823,14 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { int16_t* inputSamples = reinterpret_cast(inputByteArray.data()); int16_t* loopbackSamples = reinterpret_cast(loopBackByteArray.data()); - auto NO_RESAMPLER = nullptr; - possibleResampling(NO_RESAMPLER, - inputSamples, loopbackSamples, - numInputSamples, numLoopbackSamples, - _inputFormat, _outputFormat); + // upmix mono to stereo + if (!sampleChannelConversion(inputSamples, loopbackSamples, numInputSamples, _inputFormat, _outputFormat)) { + // no conversion, just copy the samples + memcpy(loopbackSamples, inputSamples, numInputSamples * sizeof(int16_t)); + } // apply stereo reverb at the source, to the loopback audio if (!_shouldEchoLocally && hasReverb) { - assert(_outputFormat.channelCount() == 2); updateReverbOptions(); _sourceReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); } From 25920732ec5585dd39b7a093758c5aba4b7d0f02 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 14 Sep 2016 08:23:53 -0700 Subject: [PATCH 021/126] Remove unused buffer --- libraries/audio-client/src/AudioClient.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 4a75b38bbb..36cda8050e 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -253,7 +253,6 @@ private: Gate _gate; Mutex _injectorsMutex; - QByteArray firstInputFrame; QAudioInput* _audioInput; QAudioFormat _desiredInputFormat; QAudioFormat _inputFormat; From e82d751dace2b93b9cc99d6601954557c568b015 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 14 Sep 2016 08:25:41 -0700 Subject: [PATCH 022/126] Fix typo --- libraries/audio-client/src/AudioClient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 1c4cde8204..0ad77f996f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -927,12 +927,12 @@ void AudioClient::handleAudioInput() { audioTransform.setRotation(_orientationGetter()); // FIXME find a way to properly handle both playback audio and user audio concurrently - QByteArray decocedBuffer(reinterpret_cast(networkAudioSamples), numNetworkBytes); + QByteArray decodedBuffer(reinterpret_cast(networkAudioSamples), numNetworkBytes); QByteArray encodedBuffer; if (_encoder) { - _encoder->encode(decocedBuffer, encodedBuffer); + _encoder->encode(decodedBuffer, encodedBuffer); } else { - encodedBuffer = decocedBuffer; + encodedBuffer = decodedBuffer; } emitAudioPacket(encodedBuffer.constData(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, audioTransform, packetType, _selectedCodecName); From ad97a15e8b970c56e9aaa31544f044a615854c72 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 14 Sep 2016 09:54:15 -0700 Subject: [PATCH 023/126] Handle another case when resampling is not needed --- libraries/audio-client/src/AudioClient.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 0ad77f996f..99922284dc 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -839,8 +839,12 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { } void AudioClient::handleAudioInput() { + // input samples required to produce exactly NETWORK_FRAME_SAMPLES of output - const int inputSamplesRequired = _inputFormat.channelCount() * _inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + const int inputSamplesRequired = (_inputToNetworkResampler ? + _inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) : + AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) * _inputFormat.channelCount(); + const auto inputAudioSamples = std::unique_ptr(new int16_t[inputSamplesRequired]); QByteArray inputByteArray = _inputDevice->readAll(); From db20a8ceef18b0a8f184bfa044e9afe5449c821d Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 14 Sep 2016 11:20:09 -0700 Subject: [PATCH 024/126] fix 1319 --- interface/resources/qml/AddressBarDialog.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 2536fdade9..27cbab41f7 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -135,7 +135,10 @@ Window { buttonState: 1 defaultState: 1 hoverState: 2 - onClicked: addressBarDialog.loadHome(); + onClicked: { + addressBarDialog.loadHome(); + root.shown = false; + } anchors { left: parent.left leftMargin: homeButton.width / 2 From 8734661a0e383668f85097bae9b9ba234df149a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 14 Sep 2016 11:28:22 -0700 Subject: [PATCH 025/126] add explaining comment --- interface/src/avatar/AvatarActionHold.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ce4455d921..b9e830b889 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -245,6 +245,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { // 4 -- ignore i of 1 2 3 // 5 -- ignore i of 2 3 4 + // This code is now disabled, but I'm leaving it comment-out because I suspect it will come back. // if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || // (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || // (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) { From 59db640cb54c723d0c2011534663281978311d9b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 14 Sep 2016 11:33:03 -0700 Subject: [PATCH 026/126] add explaining comment --- interface/src/avatar/AvatarActionHold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b9e830b889..8b8f8e8c2e 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -245,7 +245,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { // 4 -- ignore i of 1 2 3 // 5 -- ignore i of 2 3 4 - // This code is now disabled, but I'm leaving it comment-out because I suspect it will come back. + // This code is now disabled, but I'm leaving it commented-out because I suspect it will come back. // if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || // (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || // (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) { From 03a8af76e3c3d41508cba17eb2b5eebb5ebf66c1 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 14 Sep 2016 12:02:33 -0700 Subject: [PATCH 027/126] don't do hand-controller edit object-selection when pointed at a HUD element --- scripts/system/libraries/entitySelectionTool.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 461204b7aa..9d98a19305 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1022,6 +1022,9 @@ SelectionDisplay = (function() { // No switching while the other is already triggered, so no need to release. activeHand = (activeHand === Controller.Standard.RightHand) ? Controller.Standard.LeftHand : Controller.Standard.RightHand; } + if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(Reticle.position)) { + return; + } var eventResult = that.mousePressEvent({}); if (!eventResult || (eventResult === 'selectionBox')) { var pickRay = controllerComputePickRay(); From 44703386634f112b3ae8647f197bae151c6d42b1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 14 Sep 2016 21:39:45 -0700 Subject: [PATCH 028/126] catagorize some qDebugs --- interface/resources/qml/ToolWindow.qml | 6 -- interface/resources/qml/controls/WebView.qml | 1 - interface/src/Application.cpp | 28 +++---- libraries/audio-client/src/AudioClient.cpp | 25 +++--- .../src/controllers/UserInputMapper.cpp | 10 +-- libraries/fbx/src/FBXReader_Node.cpp | 3 +- libraries/gl/src/gl/Context.cpp | 4 +- libraries/gl/src/gl/Context.h | 2 +- libraries/gl/src/gl/GLLogging.cpp | 14 ++++ libraries/gl/src/gl/GLLogging.h | 19 +++++ libraries/gl/src/gl/GLWindow.cpp | 9 ++- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 10 ++- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 13 +-- libraries/gl/src/gl/OglplusHelpers.cpp | 3 +- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 4 +- libraries/networking/src/AddressManager.cpp | 2 +- libraries/networking/src/AssetClient.cpp | 4 +- libraries/networking/src/LimitedNodeList.cpp | 4 +- .../physics/src/PhysicalEntitySimulation.cpp | 3 +- .../plugins/src/plugins/PluginLogging.cpp | 14 ++++ libraries/plugins/src/plugins/PluginLogging.h | 19 +++++ .../plugins/src/plugins/PluginManager.cpp | 21 ++--- .../procedural/src/procedural/Procedural.cpp | 2 + libraries/shared/src/SharedUtil.cpp | 79 ++++++++++--------- 24 files changed, 189 insertions(+), 110 deletions(-) create mode 100644 libraries/gl/src/gl/GLLogging.cpp create mode 100644 libraries/gl/src/gl/GLLogging.h create mode 100644 libraries/plugins/src/plugins/PluginLogging.cpp create mode 100644 libraries/plugins/src/plugins/PluginLogging.h diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml index f6a4600e06..b4ae882330 100644 --- a/interface/resources/qml/ToolWindow.qml +++ b/interface/resources/qml/ToolWindow.qml @@ -154,7 +154,6 @@ ScrollingWindow { return i; } } - console.warn("Could not find tab for " + source); return -1; } @@ -189,7 +188,6 @@ ScrollingWindow { return i; } } - console.warn("Could not find free tab"); return -1; } @@ -216,7 +214,6 @@ ScrollingWindow { var existingTabIndex = findIndexForUrl(properties.source); if (existingTabIndex >= 0) { - console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source); var tab = tabView.getTab(existingTabIndex); return tab.item; } @@ -239,16 +236,13 @@ ScrollingWindow { var tab = tabView.getTab(freeTabIndex); tab.title = properties.title || "Unknown"; tab.enabled = true; - console.log("New tab URL: " + properties.source) tab.originalUrl = properties.source; var eventBridge = properties.eventBridge; - console.log("Event bridge: " + eventBridge); var result = tab.item; result.enabled = true; tabView.tabCount++; - console.log("Setting event bridge: " + eventBridge); result.eventBridgeWrapper.eventBridge = eventBridge; result.url = properties.source; return result; diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 2f7a668d65..22c751fb24 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -44,7 +44,6 @@ Item { webChannel.registeredObjects: [eventBridgeWrapper] Component.onCompleted: { - console.log("Connecting JS messaging to Hifi Logging"); // Ensure the JS from the web-engine makes it to our logging root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ec0a2687ba..4d12e05e87 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -264,7 +264,7 @@ public: auto elapsedMovingAverage = _movingAverage.getAverage(); if (elapsedMovingAverage > _maxElapsedAverage) { - qDebug() << "DEADLOCK WATCHDOG WARNING:" + qCDebug(interfaceapp) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed @@ -274,7 +274,7 @@ public: _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { - qDebug() << "DEADLOCK WATCHDOG WARNING:" + qCDebug(interfaceapp) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "PREVIOUS maxElapsed:" << _maxElapsed @@ -284,7 +284,7 @@ public: _maxElapsed = lastHeartbeatAge; } if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { - qDebug() << "DEADLOCK WATCHDOG WARNING:" + qCDebug(interfaceapp) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" << "maxElapsed:" << _maxElapsed @@ -293,7 +293,7 @@ public: } if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { - qDebug() << "DEADLOCK DETECTED -- " + qCDebug(interfaceapp) << "DEADLOCK DETECTED -- " << "lastHeartbeatAge:" << lastHeartbeatAge << "[ lastHeartbeat :" << lastHeartbeat << "now:" << now << " ]" @@ -2005,7 +2005,7 @@ void Application::resizeGL() { static qreal lastDevicePixelRatio = 0; qreal devicePixelRatio = _window->devicePixelRatio(); if (offscreenUi->size() != fromGlm(uiSize) || devicePixelRatio != lastDevicePixelRatio) { - qDebug() << "Device pixel ratio changed, triggering resize to " << uiSize; + qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize; offscreenUi->resize(fromGlm(uiSize), true); _offscreenContext->makeCurrent(); lastDevicePixelRatio = devicePixelRatio; @@ -3260,17 +3260,17 @@ void Application::init() { Setting::Handle firstRun { Settings::firstRun, true }; if (addressLookupString.isEmpty() && firstRun.get()) { - qDebug() << "First run and no URL passed... attempting to go to Home or Entry..."; + qCDebug(interfaceapp) << "First run and no URL passed... attempting to go to Home or Entry..."; DependencyManager::get()->ifLocalSandboxRunningElse([](){ - qDebug() << "Home sandbox appears to be running, going to Home."; + qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; DependencyManager::get()->goToLocalSandbox(); }, [](){ - qDebug() << "Home sandbox does not appear to be running, going to Entry."; + qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry."; DependencyManager::get()->goToEntry(); }); } else { - qDebug() << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); + qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); DependencyManager::get()->loadSettings(addressLookupString); } @@ -5617,7 +5617,7 @@ void Application::setActiveDisplayPlugin(const QString& pluginName) { void Application::handleLocalServerConnection() const { auto server = qobject_cast(sender()); - qDebug() << "Got connection on local server from additional instance - waiting for parameters"; + qCDebug(interfaceapp) << "Got connection on local server from additional instance - waiting for parameters"; auto socket = server->nextPendingConnection(); @@ -5633,7 +5633,7 @@ void Application::readArgumentsFromLocalSocket() const { auto message = socket->readAll(); socket->deleteLater(); - qDebug() << "Read from connection: " << message; + qCDebug(interfaceapp) << "Read from connection: " << message; // If we received a message, try to open it as a URL if (message.length() > 0) { @@ -5735,8 +5735,8 @@ void Application::updateThreadPoolCount() const { auto reservedThreads = UI_RESERVED_THREADS + OS_RESERVED_THREADS + _displayPlugin->getRequiredThreadCount(); auto availableThreads = QThread::idealThreadCount() - reservedThreads; auto threadPoolSize = std::max(MIN_PROCESSING_THREAD_POOL_SIZE, availableThreads); - qDebug() << "Ideal Thread Count " << QThread::idealThreadCount(); - qDebug() << "Reserved threads " << reservedThreads; - qDebug() << "Setting thread pool size to " << threadPoolSize; + qCDebug(interfaceapp) << "Ideal Thread Count " << QThread::idealThreadCount(); + qCDebug(interfaceapp) << "Reserved threads " << reservedThreads; + qCDebug(interfaceapp) << "Setting thread pool size to " << threadPoolSize; QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize); } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 99922284dc..7d313fdca2 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -182,7 +182,7 @@ AudioClient::~AudioClient() { } void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { - qDebug() << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec; + qCDebug(audioclient) << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec; selectAudioFormat(recievedCodec); } @@ -632,7 +632,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { _selectedCodecName = selectedCodecName; - qDebug() << "Selected Codec:" << _selectedCodecName; + qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName; // release any old codec encoder/decoder first... if (_codec && _encoder) { @@ -648,7 +648,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { _codec = plugin; _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); - qDebug() << "Selected Codec Plugin:" << _codec.get(); + qCDebug(audioclient) << "Selected Codec Plugin:" << _codec.get(); break; } } @@ -997,21 +997,21 @@ void AudioClient::mixLocalAudioInjectors(float* mixBuffer) { } else { - qDebug() << "injector has no more data, marking finished for removal"; + qCDebug(audioclient) << "injector has no more data, marking finished for removal"; injector->finishLocalInjection(); injectorsToRemove.append(injector); } } else { - qDebug() << "injector has no local buffer, marking as finished for removal"; + qCDebug(audioclient) << "injector has no local buffer, marking as finished for removal"; injector->finishLocalInjection(); injectorsToRemove.append(injector); } } for (AudioInjector* injector : injectorsToRemove) { - qDebug() << "removing injector"; + qCDebug(audioclient) << "removing injector"; getActiveLocalAudioInjectors().removeOne(injector); } } @@ -1106,10 +1106,10 @@ bool AudioClient::outputLocalInjector(bool isStereo, AudioInjector* injector) { // Since this is invoked with invokeMethod, there _should_ be // no reason to lock access to the vector of injectors. if (!_activeLocalAudioInjectors.contains(injector)) { - qDebug() << "adding new injector"; + qCDebug(audioclient) << "adding new injector"; _activeLocalAudioInjectors.append(injector); } else { - qDebug() << "injector exists in active list already"; + qCDebug(audioclient) << "injector exists in active list already"; } return true; @@ -1204,7 +1204,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn void AudioClient::outputNotify() { int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads(); if (recentUnfulfilled > 0) { - qCInfo(audioclient, "Starve detected, %d new unfulfilled reads", recentUnfulfilled); + qCDebug(audioclient, "Starve detected, %d new unfulfilled reads", recentUnfulfilled); if (_outputStarveDetectionEnabled.get()) { quint64 now = usecTimestampNow() / 1000; @@ -1219,7 +1219,8 @@ void AudioClient::outputNotify() { int newOutputBufferSizeFrames = setOutputBufferSize(oldOutputBufferSizeFrames + 1, false); if (newOutputBufferSizeFrames > oldOutputBufferSizeFrames) { - qCInfo(audioclient, "Starve threshold surpassed (%d starves in %d ms)", _outputStarveDetectionCount, dt); + qCDebug(audioclient, + "Starve threshold surpassed (%d starves in %d ms)", _outputStarveDetectionCount, dt); } _outputStarveDetectionStartTimeMsec = now; @@ -1460,10 +1461,10 @@ void AudioClient::loadSettings() { _receivedAudioStream.setWindowSecondsForDesiredReduction(windowSecondsForDesiredReduction.get()); _receivedAudioStream.setRepetitionWithFade(repetitionWithFade.get()); - qDebug() << "---- Initializing Audio Client ----"; + qCDebug(audioclient) << "---- Initializing Audio Client ----"; auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); for (auto& plugin : codecPlugins) { - qDebug() << "Codec available:" << plugin->getName(); + qCDebug(audioclient) << "Codec available:" << plugin->getName(); } } diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index ff44d5d13d..fe50f023c3 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -665,7 +665,7 @@ Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) { if (_mappingsByName.count(mappingName)) { qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName; } - qDebug() << "Creating new Mapping " << mappingName; + qCDebug(controllers) << "Creating new Mapping " << mappingName; auto mapping = std::make_shared(mappingName); _mappingsByName[mappingName] = mapping; return mapping; @@ -1121,15 +1121,15 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) { QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error); // check validity of the document if (doc.isNull()) { - qDebug() << "Invalid JSON...\n"; - qDebug() << error.errorString(); - qDebug() << "JSON was:\n" << json << endl; + qCDebug(controllers) << "Invalid JSON...\n"; + qCDebug(controllers) << error.errorString(); + qCDebug(controllers) << "JSON was:\n" << json << endl; return Mapping::Pointer(); } if (!doc.isObject()) { qWarning() << "Mapping json Document is not an object" << endl; - qDebug() << "JSON was:\n" << json << endl; + qCDebug(controllers) << "JSON was:\n" << json << endl; return Mapping::Pointer(); } return parseMapping(doc.object()); diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXReader_Node.cpp index 7bacdbc607..44bb4ac48b 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXReader_Node.cpp @@ -22,6 +22,7 @@ #include #include +#include "ModelFormatLogging.h" template int streamSize() { return sizeof(T); @@ -356,7 +357,7 @@ FBXNode FBXReader::parseFBX(QIODevice* device) { quint32 fileVersion; in >> fileVersion; position += sizeof(fileVersion); - qDebug() << "fileVersion:" << fileVersion; + qCDebug(modelformat) << "fileVersion:" << fileVersion; bool has64BitPositions = (fileVersion >= VERSION_FBX2016); // parse the top-level node diff --git a/libraries/gl/src/gl/Context.cpp b/libraries/gl/src/gl/Context.cpp index 27e1e67560..5b8a1a2fa1 100644 --- a/libraries/gl/src/gl/Context.cpp +++ b/libraries/gl/src/gl/Context.cpp @@ -20,6 +20,8 @@ #include #include +#include "GLLogging.h" + #ifdef Q_OS_WIN @@ -111,7 +113,7 @@ void GLAPIENTRY debugMessageCallback(GLenum source, GLenum type, GLuint id, GLen if (GL_DEBUG_SEVERITY_NOTIFICATION == severity) { return; } - qDebug() << "QQQ " << message; + qCDebug(glLogging) << "QQQ " << message; } // FIXME build the PFD based on the diff --git a/libraries/gl/src/gl/Context.h b/libraries/gl/src/gl/Context.h index 96e6c693fb..6dc859f222 100644 --- a/libraries/gl/src/gl/Context.h +++ b/libraries/gl/src/gl/Context.h @@ -65,7 +65,7 @@ class Context { QWindow* _window { nullptr }; public: virtual ~OffscreenContext(); - virtual void create(); + void create() override; }; } diff --git a/libraries/gl/src/gl/GLLogging.cpp b/libraries/gl/src/gl/GLLogging.cpp new file mode 100644 index 0000000000..18d2023acd --- /dev/null +++ b/libraries/gl/src/gl/GLLogging.cpp @@ -0,0 +1,14 @@ +// +// GLLogging.cpp +// libraries/gl/src/gl/ +// +// Created by Seth Alves on 2016-9-14. +// Copyright 2016 High Fidelity, Inc. +// +// Distribucted under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLLogging.h" + +Q_LOGGING_CATEGORY(glLogging, "hifi.glLogging") diff --git a/libraries/gl/src/gl/GLLogging.h b/libraries/gl/src/gl/GLLogging.h new file mode 100644 index 0000000000..1249f4d38e --- /dev/null +++ b/libraries/gl/src/gl/GLLogging.h @@ -0,0 +1,19 @@ +// +// GLLogging.h +// libraries/gl/src/gl/ +// +// Created by Seth Alves on 2016-9-14. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GLLogging_h +#define hifi_GLLogging_h + +#include + +Q_DECLARE_LOGGING_CATEGORY(glLogging) + +#endif // hifi_GLLogging_h diff --git a/libraries/gl/src/gl/GLWindow.cpp b/libraries/gl/src/gl/GLWindow.cpp index e553290a04..c40301deb0 100644 --- a/libraries/gl/src/gl/GLWindow.cpp +++ b/libraries/gl/src/gl/GLWindow.cpp @@ -12,6 +12,7 @@ #include #include "GLHelpers.h" +#include "GLLogging.h" void GLWindow::createContext(QOpenGLContext* shareContext) { createContext(getDefaultOpenGLSurfaceFormat(), shareContext); @@ -41,10 +42,10 @@ bool GLWindow::makeCurrent() { Q_ASSERT(makeCurrentResult); std::call_once(_reportOnce, []{ - qDebug() << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); - qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); - qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); - qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); + qCDebug(glLogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); + qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); + qCDebug(glLogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); + qCDebug(glLogging) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); }); Q_ASSERT(_context == QOpenGLContext::currentContext()); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 3204b50d19..dbd338bc34 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -18,6 +18,8 @@ #include #include "GLHelpers.h" +#include "GLLogging.h" + OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){ } @@ -56,10 +58,10 @@ bool OffscreenGLCanvas::makeCurrent() { Q_ASSERT(result); std::call_once(_reportOnce, [this]{ - qDebug() << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); - qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); - qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); - qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); + qCDebug(glLogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); + qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); + qCDebug(glLogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); + qCDebug(glLogging) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); }); return result; diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 5ab2678474..6a16256198 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -32,6 +32,7 @@ #include "OffscreenGLCanvas.h" #include "GLEscrow.h" #include "GLHelpers.h" +#include "GLLogging.h" QString fixupHifiUrl(const QString& urlString) { @@ -196,7 +197,7 @@ QEvent* OffscreenQmlRenderThread::Queue::take() { OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) { _canvas.setObjectName("OffscreenQmlRenderCanvas"); - qDebug() << "Building QML Renderer"; + qCDebug(glLogging) << "Building QML Renderer"; if (!_canvas.create(shareContext)) { qWarning("Failed to create OffscreenGLCanvas"); _quit = true; @@ -223,7 +224,7 @@ OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, } void OffscreenQmlRenderThread::run() { - qDebug() << "Starting QML Renderer thread"; + qCDebug(glLogging) << "Starting QML Renderer thread"; while (!_quit) { QEvent* e = _queue.take(); @@ -282,7 +283,7 @@ QJsonObject OffscreenQmlRenderThread::getGLContextData() { } void OffscreenQmlRenderThread::init() { - qDebug() << "Initializing QML Renderer"; + qCDebug(glLogging) << "Initializing QML Renderer"; if (!_canvas.makeCurrent()) { qWarning("Failed to make context current on QML Renderer Thread"); @@ -341,7 +342,7 @@ void OffscreenQmlRenderThread::resize() { return; } - qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio; + qCDebug(glLogging) << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio; _size = newOffscreenSize; } @@ -426,7 +427,7 @@ OffscreenQmlSurface::~OffscreenQmlSurface() { QObject::disconnect(&_updateTimer); QObject::disconnect(qApp); - qDebug() << "Stopping QML Renderer Thread " << _renderer->currentThreadId(); + qCDebug(glLogging) << "Stopping QML Renderer Thread " << _renderer->currentThreadId(); _renderer->_queue.add(STOP); if (!_renderer->wait(MAX_SHUTDOWN_WAIT_SECS * USECS_PER_SECOND)) { qWarning() << "Failed to shut down the QML Renderer Thread"; @@ -443,7 +444,7 @@ void OffscreenQmlSurface::onAboutToQuit() { } void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { - qDebug() << "Building QML surface"; + qCDebug(glLogging) << "Building QML surface"; _renderer = new OffscreenQmlRenderThread(this, shareContext); _renderer->moveToThread(_renderer); diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp index d31800dc4c..fc02d75329 100644 --- a/libraries/gl/src/gl/OglplusHelpers.cpp +++ b/libraries/gl/src/gl/OglplusHelpers.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "GLLogging.h" using namespace oglplus; using namespace oglplus::shapes; @@ -190,7 +191,7 @@ public: const int stacks_) { //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm if (fov >= PI) { - qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; + qCDebug(glLogging) << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; } int gridSize = std::max(slices_, stacks_); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 98a073e283..e3f391126b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -44,10 +44,10 @@ BackendPointer GLBackend::createBackend() { auto version = QOpenGLContextWrapper::currentContextVersion(); std::shared_ptr result; if (!disableOpenGL45 && version >= 0x0405) { - qDebug() << "Using OpenGL 4.5 backend"; + qCDebug(gpugllogging) << "Using OpenGL 4.5 backend"; result = std::make_shared(); } else { - qDebug() << "Using OpenGL 4.1 backend"; + qCDebug(gpugllogging) << "Using OpenGL 4.1 backend"; result = std::make_shared(); } result->initInput(); diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index b4145c73f5..f7f305dcc8 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -765,7 +765,7 @@ void AddressManager::handleShareableNameAPIResponse(QNetworkReply& requestReply) } if (shareableNameChanged) { - qDebug() << "AddressManager shareable name changed to" << _shareablePlaceName; + qCDebug(networking) << "AddressManager shareable name changed to" << _shareablePlaceName; } } } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index c4ec0ad61e..9583d4735d 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -60,7 +60,7 @@ void AssetClient::init() { cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); cache->setCacheDirectory(cachePath); networkAccessManager.setCache(cache); - qDebug() << "ResourceManager disk cache setup at" << cachePath + qInfo() << "ResourceManager disk cache setup at" << cachePath << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; } } @@ -91,7 +91,7 @@ void AssetClient::clearCache() { } if (auto cache = NetworkAccessManager::getInstance().cache()) { - qDebug() << "AssetClient::clearCache(): Clearing disk cache."; + qInfo() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); } else { qCWarning(asset_client) << "No disk cache to clear."; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 7fad66d608..5aa31efea4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -351,7 +351,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& return sendPacket(std::move(packet), *activeSocket, destinationNode.getConnectionSecret()); } else { - qDebug() << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending"; + qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending"; return 0; } } @@ -389,7 +389,7 @@ qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const Node& des emit dataSent(destinationNode.getType(), bytesSent); return bytesSent; } else { - qDebug() << "LimitedNodeList::sendPacketList called without active socket for node" << destinationNode + qCDebug(networking) << "LimitedNodeList::sendPacketList called without active socket for node" << destinationNode << " - not sending."; return 0; } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index be420604b3..903b160a5e 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -322,7 +322,8 @@ void PhysicalEntitySimulation::addAction(EntityActionPointer action) { QMutexLocker lock(&_mutex); const QUuid& actionID = action->getID(); if (_physicsEngine->getActionByID(actionID)) { - qDebug() << "warning -- PhysicalEntitySimulation::addAction -- adding an action that was already in _physicsEngine"; + qCDebug(physics) << "warning -- PhysicalEntitySimulation::addAction -- adding an " + "action that was already in _physicsEngine"; } } EntitySimulation::addAction(action); diff --git a/libraries/plugins/src/plugins/PluginLogging.cpp b/libraries/plugins/src/plugins/PluginLogging.cpp new file mode 100644 index 0000000000..c6c218acb4 --- /dev/null +++ b/libraries/plugins/src/plugins/PluginLogging.cpp @@ -0,0 +1,14 @@ +// +// PluginLogging.cpp +// libraries/gl/src/gl/ +// +// Created by Seth Alves on 2016-9-14. +// Copyright 2016 High Fidelity, Inc. +// +// Distribucted under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "PluginLogging.h" + +Q_LOGGING_CATEGORY(plugins, "hifi.plugins") diff --git a/libraries/plugins/src/plugins/PluginLogging.h b/libraries/plugins/src/plugins/PluginLogging.h new file mode 100644 index 0000000000..65fd352244 --- /dev/null +++ b/libraries/plugins/src/plugins/PluginLogging.h @@ -0,0 +1,19 @@ +// +// PluginLogging.h +// libraries/gl/src/gl/ +// +// Created by Seth Alves on 2016-9-14. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PluginLogging_h +#define hifi_PluginLogging_h + +#include + +Q_DECLARE_LOGGING_CATEGORY(plugins) + +#endif // hifi_PluginLogging_h diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 2e60eae678..4baf20c338 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -21,6 +21,7 @@ #include "CodecPlugin.h" #include "DisplayPlugin.h" #include "InputPlugin.h" +#include "PluginLogging.h" PluginManager* PluginManager::getInstance() { @@ -87,10 +88,10 @@ const LoaderList& getLoadedPlugins() { QDir pluginDir(pluginPath); pluginDir.setFilter(QDir::Files); if (pluginDir.exists()) { - qDebug() << "Loading runtime plugins from " << pluginPath; + qInfo() << "Loading runtime plugins from " << pluginPath; auto candidates = pluginDir.entryList(); for (auto plugin : candidates) { - qDebug() << "Attempting plugin" << qPrintable(plugin); + qCDebug(plugins) << "Attempting plugin" << qPrintable(plugin); QSharedPointer loader(new QPluginLoader(pluginPath + plugin)); if (isDisabled(loader->metaData())) { @@ -100,11 +101,11 @@ const LoaderList& getLoadedPlugins() { } if (loader->load()) { - qDebug() << "Plugin" << qPrintable(plugin) << "loaded successfully"; + qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "loaded successfully"; loadedPlugins.push_back(loader); } else { - qDebug() << "Plugin" << qPrintable(plugin) << "failed to load:"; - qDebug() << " " << qPrintable(loader->errorString()); + qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "failed to load:"; + qCDebug(plugins) << " " << qPrintable(loader->errorString()); } } } @@ -139,7 +140,7 @@ const CodecPluginList& PluginManager::getCodecPlugins() { plugin->setContainer(_container); plugin->init(); - qDebug() << "init codec:" << plugin->getName(); + qCDebug(plugins) << "init codec:" << plugin->getName(); } }); return codecPlugins; @@ -157,11 +158,11 @@ static DisplayPluginList displayPlugins; const DisplayPluginList& PluginManager::getDisplayPlugins() { static std::once_flag once; static auto deviceAddedCallback = [](QString deviceName) { - qDebug() << "Added device: " << deviceName; + qCDebug(plugins) << "Added device: " << deviceName; UserActivityLogger::getInstance().connectedDevice("display", deviceName); }; static auto subdeviceAddedCallback = [](QString pluginName, QString deviceName) { - qDebug() << "Added subdevice: " << deviceName; + qCDebug(plugins) << "Added subdevice: " << deviceName; UserActivityLogger::getInstance().connectedDevice("display", pluginName + " | " + deviceName); }; @@ -204,11 +205,11 @@ const InputPluginList& PluginManager::getInputPlugins() { static InputPluginList inputPlugins; static std::once_flag once; static auto deviceAddedCallback = [](QString deviceName) { - qDebug() << "Added device: " << deviceName; + qCDebug(plugins) << "Added device: " << deviceName; UserActivityLogger::getInstance().connectedDevice("input", deviceName); }; static auto subdeviceAddedCallback = [](QString pluginName, QString deviceName) { - qDebug() << "Added subdevice: " << deviceName; + qCDebug(plugins) << "Added subdevice: " << deviceName; UserActivityLogger::getInstance().connectedDevice("input", pluginName + " | " + deviceName); }; diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 1c5ba40891..a995ad5b2f 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -121,7 +121,9 @@ bool Procedural::parseShader(const QUrl& shaderPath) { if (_shaderUrl.isLocalFile()) { _shaderPath = _shaderUrl.toLocalFile(); +#if WANT_DEBUG qDebug() << "Shader path: " << _shaderPath; +#endif if (!QFile(_shaderPath).exists()) { _networkShader.reset(); return false;; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index edb6fe437d..bb5d326851 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -767,72 +767,79 @@ void disableQtBearerPoll() { void printSystemInformation() { // Write system information to log - qDebug() << "Build Information"; - qDebug().noquote() << "\tBuild ABI: " << QSysInfo::buildAbi(); - qDebug().noquote() << "\tBuild CPU Architecture: " << QSysInfo::buildCpuArchitecture(); + qCDebug(shared) << "Build Information"; + qCDebug(shared).noquote() << "\tBuild ABI: " << QSysInfo::buildAbi(); + qCDebug(shared).noquote() << "\tBuild CPU Architecture: " << QSysInfo::buildCpuArchitecture(); - qDebug().noquote() << "System Information"; - qDebug().noquote() << "\tProduct Name: " << QSysInfo::prettyProductName(); - qDebug().noquote() << "\tCPU Architecture: " << QSysInfo::currentCpuArchitecture(); - qDebug().noquote() << "\tKernel Type: " << QSysInfo::kernelType(); - qDebug().noquote() << "\tKernel Version: " << QSysInfo::kernelVersion(); + qCDebug(shared).noquote() << "System Information"; + qCDebug(shared).noquote() << "\tProduct Name: " << QSysInfo::prettyProductName(); + qCDebug(shared).noquote() << "\tCPU Architecture: " << QSysInfo::currentCpuArchitecture(); + qCDebug(shared).noquote() << "\tKernel Type: " << QSysInfo::kernelType(); + qCDebug(shared).noquote() << "\tKernel Version: " << QSysInfo::kernelVersion(); auto macVersion = QSysInfo::macVersion(); if (macVersion != QSysInfo::MV_None) { - qDebug() << "\tMac Version: " << macVersion; + qCDebug(shared) << "\tMac Version: " << macVersion; } auto windowsVersion = QSysInfo::windowsVersion(); if (windowsVersion != QSysInfo::WV_None) { - qDebug() << "\tWindows Version: " << windowsVersion; + qCDebug(shared) << "\tWindows Version: " << windowsVersion; } #ifdef Q_OS_WIN SYSTEM_INFO si; GetNativeSystemInfo(&si); - qDebug() << "SYSTEM_INFO"; - qDebug().noquote() << "\tOEM ID: " << si.dwOemId; - qDebug().noquote() << "\tProcessor Architecture: " << si.wProcessorArchitecture; - qDebug().noquote() << "\tProcessor Type: " << si.dwProcessorType; - qDebug().noquote() << "\tProcessor Level: " << si.wProcessorLevel; - qDebug().noquote() << "\tProcessor Revision: " + qCDebug(shared) << "SYSTEM_INFO"; + qCDebug(shared).noquote() << "\tOEM ID: " << si.dwOemId; + qCDebug(shared).noquote() << "\tProcessor Architecture: " << si.wProcessorArchitecture; + qCDebug(shared).noquote() << "\tProcessor Type: " << si.dwProcessorType; + qCDebug(shared).noquote() << "\tProcessor Level: " << si.wProcessorLevel; + qCDebug(shared).noquote() << "\tProcessor Revision: " << QString("0x%1").arg(si.wProcessorRevision, 4, 16, QChar('0')); - qDebug().noquote() << "\tNumber of Processors: " << si.dwNumberOfProcessors; - qDebug().noquote() << "\tPage size: " << si.dwPageSize << " Bytes"; - qDebug().noquote() << "\tMin Application Address: " + qCDebug(shared).noquote() << "\tNumber of Processors: " << si.dwNumberOfProcessors; + qCDebug(shared).noquote() << "\tPage size: " << si.dwPageSize << " Bytes"; + qCDebug(shared).noquote() << "\tMin Application Address: " << QString("0x%1").arg(qulonglong(si.lpMinimumApplicationAddress), 16, 16, QChar('0')); - qDebug().noquote() << "\tMax Application Address: " + qCDebug(shared).noquote() << "\tMax Application Address: " << QString("0x%1").arg(qulonglong(si.lpMaximumApplicationAddress), 16, 16, QChar('0')); const double BYTES_TO_MEGABYTE = 1.0 / (1024 * 1024); - qDebug() << "MEMORYSTATUSEX"; + qCDebug(shared) << "MEMORYSTATUSEX"; MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); if (GlobalMemoryStatusEx(&ms)) { - qDebug().noquote() << QString("\tCurrent System Memory Usage: %1%").arg(ms.dwMemoryLoad); - qDebug().noquote() << QString("\tAvail Physical Memory: %1 MB").arg(ms.ullAvailPhys * BYTES_TO_MEGABYTE, 20, 'f', 2); - qDebug().noquote() << QString("\tTotal Physical Memory: %1 MB").arg(ms.ullTotalPhys * BYTES_TO_MEGABYTE, 20, 'f', 2); - qDebug().noquote() << QString("\tAvail in Page File: %1 MB").arg(ms.ullAvailPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2); - qDebug().noquote() << QString("\tTotal in Page File: %1 MB").arg(ms.ullTotalPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2); - qDebug().noquote() << QString("\tAvail Virtual Memory: %1 MB").arg(ms.ullAvailVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2); - qDebug().noquote() << QString("\tTotal Virtual Memory: %1 MB").arg(ms.ullTotalVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2); + qCDebug(shared).noquote() + << QString("\tCurrent System Memory Usage: %1%").arg(ms.dwMemoryLoad); + qCDebug(shared).noquote() + << QString("\tAvail Physical Memory: %1 MB").arg(ms.ullAvailPhys * BYTES_TO_MEGABYTE, 20, 'f', 2); + qCDebug(shared).noquote() + << QString("\tTotal Physical Memory: %1 MB").arg(ms.ullTotalPhys * BYTES_TO_MEGABYTE, 20, 'f', 2); + qCDebug(shared).noquote() + << QString("\tAvail in Page File: %1 MB").arg(ms.ullAvailPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2); + qCDebug(shared).noquote() + << QString("\tTotal in Page File: %1 MB").arg(ms.ullTotalPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2); + qCDebug(shared).noquote() + << QString("\tAvail Virtual Memory: %1 MB").arg(ms.ullAvailVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2); + qCDebug(shared).noquote() + << QString("\tTotal Virtual Memory: %1 MB").arg(ms.ullTotalVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2); } else { - qDebug() << "\tFailed to retrieve memory status: " << GetLastError(); + qCDebug(shared) << "\tFailed to retrieve memory status: " << GetLastError(); } - qDebug() << "CPUID"; + qCDebug(shared) << "CPUID"; - qDebug() << "\tCPU Vendor: " << CPUIdent::Vendor().c_str(); - qDebug() << "\tCPU Brand: " << CPUIdent::Brand().c_str(); + qCDebug(shared) << "\tCPU Vendor: " << CPUIdent::Vendor().c_str(); + qCDebug(shared) << "\tCPU Brand: " << CPUIdent::Brand().c_str(); for (auto& feature : CPUIdent::getAllFeatures()) { - qDebug().nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str(); + qCDebug(shared).nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str(); } #endif - qDebug() << "Environment Variables"; + qCDebug(shared) << "Environment Variables"; // List of env variables to include in the log. For privacy reasons we don't send all env variables. const QStringList envWhitelist = { "QTWEBENGINE_REMOTE_DEBUGGING" @@ -840,7 +847,7 @@ void printSystemInformation() { auto envVariables = QProcessEnvironment::systemEnvironment(); for (auto& env : envWhitelist) { - qDebug().noquote().nospace() << "\t" << + qCDebug(shared).noquote().nospace() << "\t" << (envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND"); } } @@ -869,4 +876,4 @@ bool getMemoryInfo(MemoryInfo& info) { #endif return false; -} \ No newline at end of file +} From d67701f7bb963d4aad5344c568c21d393e8fe3b1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 15 Sep 2016 13:02:18 -0700 Subject: [PATCH 029/126] new logging category for deadlock debug prints --- interface/src/Application.cpp | 8 ++++---- interface/src/InterfaceLogging.cpp | 1 + interface/src/InterfaceLogging.h | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4d12e05e87..ebe7124d46 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -264,7 +264,7 @@ public: auto elapsedMovingAverage = _movingAverage.getAverage(); if (elapsedMovingAverage > _maxElapsedAverage) { - qCDebug(interfaceapp) << "DEADLOCK WATCHDOG WARNING:" + qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed @@ -274,7 +274,7 @@ public: _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { - qCDebug(interfaceapp) << "DEADLOCK WATCHDOG WARNING:" + qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "PREVIOUS maxElapsed:" << _maxElapsed @@ -284,7 +284,7 @@ public: _maxElapsed = lastHeartbeatAge; } if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { - qCDebug(interfaceapp) << "DEADLOCK WATCHDOG WARNING:" + qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" << "maxElapsed:" << _maxElapsed @@ -293,7 +293,7 @@ public: } if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { - qCDebug(interfaceapp) << "DEADLOCK DETECTED -- " + qCDebug(interfaceapp_deadlock) << "DEADLOCK DETECTED -- " << "lastHeartbeatAge:" << lastHeartbeatAge << "[ lastHeartbeat :" << lastHeartbeat << "now:" << now << " ]" diff --git a/interface/src/InterfaceLogging.cpp b/interface/src/InterfaceLogging.cpp index 0afcb30c27..49fb0bd640 100644 --- a/interface/src/InterfaceLogging.cpp +++ b/interface/src/InterfaceLogging.cpp @@ -13,3 +13,4 @@ Q_LOGGING_CATEGORY(interfaceapp, "hifi.interface") Q_LOGGING_CATEGORY(interfaceapp_timing, "hifi.interface.timing") +Q_LOGGING_CATEGORY(interfaceapp_deadlock, "hifi.interface.deadlock") diff --git a/interface/src/InterfaceLogging.h b/interface/src/InterfaceLogging.h index be2ee73fba..64eedbda4d 100644 --- a/interface/src/InterfaceLogging.h +++ b/interface/src/InterfaceLogging.h @@ -16,5 +16,6 @@ Q_DECLARE_LOGGING_CATEGORY(interfaceapp) Q_DECLARE_LOGGING_CATEGORY(interfaceapp_timing) +Q_DECLARE_LOGGING_CATEGORY(interfaceapp_deadlock) #endif // hifi_InterfaceLogging_h From 6a32ef29dc1dd5b1fa7ab070f83b3005b6f5e24b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 15 Sep 2016 13:02:33 -0700 Subject: [PATCH 030/126] Fix eventBridgeLoader path in particle explorer --- scripts/system/particle_explorer/particleExplorer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/particle_explorer/particleExplorer.html b/scripts/system/particle_explorer/particleExplorer.html index 1de176214c..260d8a7813 100644 --- a/scripts/system/particle_explorer/particleExplorer.html +++ b/scripts/system/particle_explorer/particleExplorer.html @@ -17,7 +17,7 @@ - +