From 7da0935db2bd50633a04ba24f3e6b54b2bd9df65 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 13 Apr 2016 12:41:49 -0700 Subject: [PATCH 01/36] grab.js will do heart-beat in userData so handControllerGrab.js wont see it as an abandoned grab --- examples/grab.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/examples/grab.js b/examples/grab.js index f9d1f41b97..8857b5f611 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -29,6 +29,10 @@ var IDENTITY_QUAT = { var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js var GRAB_USER_DATA_KEY = "grabKey"; // shared with handControllerGrab.js +var MSECS_PER_SEC = 1000.0; +var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC; +var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC; + var DEFAULT_GRABBABLE_DATA = { grabbable: true, invertSolidWhileHeld: false @@ -335,6 +339,9 @@ Grabber.prototype.pressEvent = function(event) { mouse.startDrag(event); + var now = Date.now(); + this.lastHeartBeat = 0; + var clickedEntity = pickResults.entityID; var entityProperties = Entities.getEntityProperties(clickedEntity) this.startPosition = entityProperties.position; @@ -399,12 +406,26 @@ Grabber.prototype.releaseEvent = function(event) { } } + +Grabber.prototype.heartBeat = function(entityID) { + var now = Date.now(); + if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["heartBeat"] = now; + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + this.lastHeartBeat = now; + } +}; + + Grabber.prototype.moveEvent = function(event) { if (!this.isGrabbing) { return; } mouse.updateDrag(event); + this.heartBeat(this.entityID); + // see if something added/restored gravity var entityProperties = Entities.getEntityProperties(this.entityID); if (Vec3.length(entityProperties.gravity) != 0) { From 000d6c8a68d89063648147dc7ce1500208bd71bf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 13 Apr 2016 12:48:05 -0700 Subject: [PATCH 02/36] when doing a parenting grab of something that already has an action, set the parent back to null when releasing --- examples/controllers/handControllerGrab.js | 27 ++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4b20651899..f0966ac53b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -102,7 +102,6 @@ var ZERO_VEC = { }; var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; -var MSEC_PER_SEC = 1000.0; // these control how long an abandoned pointer line or action will hang around var LIFETIME = 10; @@ -837,7 +836,7 @@ function MyController(hand) { this.search = function() { this.grabbedEntity = null; this.isInitialGrab = false; - this.doubleParentGrab = false; + this.shouldResetParentOnRelease = false; this.checkForStrayChildren(); @@ -914,7 +913,7 @@ function MyController(hand) { candidateEntities = rayPickedCandidateEntities.concat(nearPickedCandidateEntities); var forbiddenNames = ["Grab Debug Entity", "grab pointer"]; - var forbiddenTypes = ['Unknown', 'Light', 'ParticleEffect', 'PolyLine', 'Zone']; + var forbiddenTypes = ['Unknown', 'Light', 'PolyLine', 'Zone']; var minDistance = PICK_MAX_DISTANCE; var i, props, distance, grabbableData; @@ -1019,6 +1018,10 @@ function MyController(hand) { if (this.state == STATE_SEARCHING) { this.setState(STATE_NEAR_GRABBING); } else { // (this.state == STATE_HOLD_SEARCHING) + // if there was already an action, we'll need to set the parent back to null once we release + this.shouldResetParentOnRelease = true; + this.previousParentID = props.parentID; + this.previousParentJointIndex = props.parentJointIndex; this.setState(STATE_HOLD); } return; @@ -1064,7 +1067,7 @@ function MyController(hand) { // it's not physical and it's already held via parenting. go ahead and grab it, but // save off the current parent and joint. this wont always be right if there are more than // two grabs and the order of release isn't opposite of the order of grabs. - this.doubleParentGrab = true; + this.shouldResetParentOnRelease = true; this.previousParentID = props.parentID; this.previousParentJointIndex = props.parentJointIndex; if (this.state == STATE_SEARCHING) { @@ -1149,7 +1152,7 @@ function MyController(hand) { if (this.actionID === NULL_UUID) { this.actionID = null; } - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); if (this.actionID !== null) { this.setState(STATE_CONTINUE_DISTANCE_HOLDING); @@ -1184,7 +1187,7 @@ function MyController(hand) { var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + var deltaTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds this.currentObjectTime = now; // the action was set up when this.distanceHolding was called. update the targets. @@ -1302,7 +1305,7 @@ function MyController(hand) { ttl: ACTION_TTL }); if (success) { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); } else { print("continueDistanceHolding -- updateAction failed"); } @@ -1327,7 +1330,7 @@ function MyController(hand) { return false; } var now = Date.now(); - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); return true; }; @@ -1563,7 +1566,7 @@ function MyController(hand) { var now = Date.now(); var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + var deltaTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds if (deltaTime > 0.0) { var worldDeltaPosition = Vec3.subtract(props.position, this.currentObjectPosition); @@ -1590,7 +1593,7 @@ function MyController(hand) { this.callEntityMethodOnGrabbed("continueNearGrab"); } - if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) { // if less than a 5 seconds left, refresh the actions ttl var success = Entities.updateAction(this.grabbedEntity, this.actionID, { hand: this.hand === RIGHT_HAND ? "right" : "left", @@ -1603,7 +1606,7 @@ function MyController(hand) { ignoreIK: this.ignoreIK }); if (success) { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); } else { print("continueNearGrabbing -- updateAction failed"); Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1881,7 +1884,7 @@ function MyController(hand) { } data = null; - } else if (this.doubleParentGrab) { + } else if (this.shouldResetParentOnRelease) { // we parent-grabbed this from another parent grab. try to put it back where we found it. var deactiveProps = { parentID: this.previousParentID, From 3186984586b3c40f37c660bf7a6fc0d9ebc3f53b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 13 Apr 2016 13:39:06 -0700 Subject: [PATCH 03/36] don't give velocity to non-physical things when they are released --- examples/controllers/handControllerGrab.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f0966ac53b..f79773fe6c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -739,10 +739,6 @@ function MyController(hand) { }; this.propsArePhysical = function(props) { - if (!props.dynamic && props.parentID != MyAvatar.sessionUUID) { - // if we have parented something, don't do this check on dynamic. - return false; - } var isPhysical = (props.shapeType && props.shapeType != 'none'); return isPhysical; } @@ -1841,12 +1837,12 @@ function MyController(hand) { // things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If // it looks like the dropped thing should fall, give it a little velocity. - var props = Entities.getEntityProperties(entityID, ["parentID", "velocity"]) + var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]) var parentID = props.parentID; var forceVelocity = false; var doSetVelocity = false; - if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID) { + if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) { // TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up // props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that // is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab From 2425baf6e698c6c91eeae15a8aba0238e2c9ea1c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 24 Apr 2016 08:14:56 -0700 Subject: [PATCH 04/36] don't early _exit on Linux --- interface/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 4b6d50c274..bf1fe1d922 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -203,7 +203,7 @@ int main(int argc, const char* argv[]) { Application::shutdownPlugins(); qCDebug(interfaceapp, "Normal exit."); -#ifndef DEBUG +#if defined(DEBUG) && !defined(Q_OS_LINUX) // HACK: exit immediately (don't handle shutdown callbacks) for Release build _exit(exitCode); #endif From c9df4468794a462f993c8ccfe40f3567df0fcdea Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 24 Apr 2016 08:15:10 -0700 Subject: [PATCH 05/36] web-entities don't yet work right on Linux --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 855fd16408..9edcd8259c 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -51,6 +51,11 @@ RenderableWebEntityItem::~RenderableWebEntityItem() { } bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { + #ifdef defined(Q_OS_LINUX) + // these don't seem to work on Linux + return false; + #endif + if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) { qWarning() << "Too many concurrent web views to create new view"; return false; From 6591329b0cb5adf3956d03cbce0f09bfa0166bb3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 26 Apr 2016 13:04:08 -0700 Subject: [PATCH 06/36] grab script calls startDistanceGrab and releaseGrab entity methods and sends grab/release messages to Hifi-Object-Manipulation channel --- examples/grab.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/examples/grab.js b/examples/grab.js index 8857b5f611..2134616f89 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -383,7 +383,16 @@ Grabber.prototype.pressEvent = function(event) { if(!entityIsGrabbedByOther(this.entityID)){ this.moveEvent(event); } - + + var args = "mouse"; + Entities.callEntityMethod(this.entityID, "startDistanceGrab", args); + + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'grab', + grabbedEntity: this.entityID + })); + + // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME }); } @@ -401,6 +410,16 @@ Grabber.prototype.releaseEvent = function(event) { beacon.disable(); + var args = "mouse"; + Entities.callEntityMethod(this.entityID, "releaseGrab", args); + + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'release', + grabbedEntity: this.entityID, + joint: "mouse" + })); + + // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME }); } From 5b8960e43c74443baecb3e0d6e4d6c4711f49ee4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 26 Apr 2016 13:04:37 -0700 Subject: [PATCH 07/36] send a grab message for action grabs, not just parenting ones --- examples/controllers/handControllerGrab.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f79773fe6c..8a7399abc2 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1435,6 +1435,10 @@ function MyController(hand) { if (!this.setupHoldAction()) { return; } + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'grab', + grabbedEntity: this.grabbedEntity + })); } else { // grab entity via parenting this.actionID = null; From 9e53055d439f9336b976182641f1b23d982d9bc5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 May 2016 15:48:50 -0700 Subject: [PATCH 08/36] parentID and parentJointIndex are now protected by simulation ownership --- libraries/entities/src/EntityItem.cpp | 9 +++++++-- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 10 ++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index dc017f81e6..7bdd88ae5a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -705,8 +705,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData); - READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); - READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + { // parentID and parentJointIndex are also protected by simulation ownership + bool oldOverwrite = overwriteLocalData; + overwriteLocalData = overwriteLocalData && !weOwnSimulation; + READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + overwriteLocalData = oldOverwrite; + } READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 92849d6e2f..738e8910fe 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1615,7 +1615,7 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) { QList EntityItemProperties::listChangedProperties() { QList out; if (containsPositionChange()) { - out += "posistion"; + out += "position"; } if (dimensionsChanged()) { out += "dimensions"; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b4f0c484d5..27655e2a98 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -213,6 +213,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); + properties.setParentID(false); + properties.setParentJointIndex(false); if (wantTerseEditLogging()) { qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed"; @@ -848,6 +850,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList Date: Wed, 4 May 2016 11:29:17 -0700 Subject: [PATCH 09/36] try having all spring derived actions agree on a target --- interface/src/avatar/AvatarActionHold.cpp | 63 ++--------- interface/src/avatar/AvatarActionHold.h | 7 +- libraries/physics/src/ObjectActionSpring.cpp | 106 +++++++++++++++--- libraries/physics/src/ObjectActionSpring.h | 10 ++ .../system/controllers/handControllerGrab.js | 4 +- 5 files changed, 112 insertions(+), 78 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 629b3aac12..c84cfecb40 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -93,13 +93,13 @@ void AvatarActionHold::prepareForPhysicsSimulation() { activateBody(true); } -std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, - glm::vec3& linearVelocity, glm::vec3& angularVelocity) { +bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity) { auto avatarManager = DependencyManager::get(); auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); if (!holdingAvatar) { - return holdingAvatar; + return false;; } withReadLock([&]{ @@ -171,62 +171,17 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); - return holdingAvatar; + return true; } void AvatarActionHold::updateActionWorker(float deltaTimeStep) { - glm::quat rotation; - glm::vec3 position; - glm::vec3 linearVelocity; - glm::vec3 angularVelocity; - bool valid = false; - int holdCount = 0; - - auto ownerEntity = _ownerEntity.lock(); - if (!ownerEntity) { - return; - } - QList holdActions = ownerEntity->getActionsOfType(ACTION_TYPE_HOLD); - foreach (EntityActionPointer action, holdActions) { - std::shared_ptr holdAction = std::static_pointer_cast(action); - glm::quat rotationForAction; - glm::vec3 positionForAction; - glm::vec3 linearVelocityForAction, angularVelocityForAction; - std::shared_ptr holdingAvatar = holdAction->getTarget(deltaTimeStep, rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction); - if (holdingAvatar) { - holdCount ++; - if (holdAction.get() == this) { - // only use the rotation for this action - valid = true; - rotation = rotationForAction; - } - - position += positionForAction; - linearVelocity += linearVelocityForAction; - angularVelocity += angularVelocityForAction; - } - } - - if (valid && holdCount > 0) { - position /= holdCount; - linearVelocity /= holdCount; - angularVelocity /= holdCount; - - withWriteLock([&]{ - _positionalTarget = position; - _rotationalTarget = rotation; - _linearVelocityTarget = linearVelocity; - _angularVelocityTarget = angularVelocity; - _positionalTargetSet = true; - _rotationalTargetSet = true; - _active = true; - }); - if (_kinematic) { + if (_kinematic) { + if (prepareForSpringUpdate(deltaTimeStep)) { doKinematicUpdate(deltaTimeStep); - } else { - forceBodyNonStatic(); - ObjectActionSpring::updateActionWorker(deltaTimeStep); } + } else { + forceBodyNonStatic(); + ObjectActionSpring::updateActionWorker(deltaTimeStep); } } diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 0ad9cff257..609fd57ff3 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -36,8 +36,8 @@ public: virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); - std::shared_ptr getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, - glm::vec3& linearVelocity, glm::vec3& angularVelocity); + virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity) override; virtual void prepareForPhysicsSimulation() override; @@ -51,9 +51,6 @@ private: QString _hand { "right" }; QUuid _holderID; - glm::vec3 _linearVelocityTarget; - glm::vec3 _angularVelocityTarget; - bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index dcd77c1010..563733ea2d 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -21,9 +21,11 @@ const uint16_t ObjectActionSpring::springVersion = 1; ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) : ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity), _positionalTarget(glm::vec3(0.0f)), + _desiredPositionalTarget(glm::vec3(0.0f)), _linearTimeScale(FLT_MAX), _positionalTargetSet(true), _rotationalTarget(glm::quat()), + _desiredRotationalTarget(glm::quat()), _angularTimeScale(FLT_MAX), _rotationalTargetSet(true) { #if WANT_DEBUG @@ -37,9 +39,82 @@ ObjectActionSpring::~ObjectActionSpring() { #endif } +bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity) { + rotation = _desiredRotationalTarget; + position = _desiredPositionalTarget; + linearVelocity = glm::vec3(); + angularVelocity = glm::vec3(); + return true; +} + + +bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { + glm::quat rotation; + glm::vec3 position; + glm::vec3 linearVelocity; + glm::vec3 angularVelocity; + + bool valid = false; + int springCount = 0; + + auto ownerEntity = _ownerEntity.lock(); + if (!ownerEntity) { + return false; + } + + QList springDerivedActions; + springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_SPRING)); + springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_HOLD)); + + foreach (EntityActionPointer action, springDerivedActions) { + std::shared_ptr springAction = std::static_pointer_cast(action); + glm::quat rotationForAction; + glm::vec3 positionForAction; + glm::vec3 linearVelocityForAction, angularVelocityForAction; + bool success = springAction->getTarget(deltaTimeStep, rotationForAction, + positionForAction, linearVelocityForAction, + angularVelocityForAction); + if (success) { + springCount ++; + if (springAction.get() == this) { + // only use the rotation for this action + valid = true; + rotation = rotationForAction; + } + + position += positionForAction; + linearVelocity += linearVelocityForAction; + angularVelocity += angularVelocityForAction; + } + } + + if (valid && springCount > 0) { + position /= springCount; + linearVelocity /= springCount; + angularVelocity /= springCount; + + withWriteLock([&]{ + _positionalTarget = position; + _rotationalTarget = rotation; + _linearVelocityTarget = linearVelocity; + _angularVelocityTarget = angularVelocity; + _positionalTargetSet = true; + _rotationalTargetSet = true; + _active = true; + }); + } + + return valid; +} + + void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { - // don't risk hanging the thread running the physics simulation - auto lockResult = withTryReadLock([&]{ + if (!prepareForSpringUpdate(deltaTimeStep)) { + return; + } + + withReadLock([&]{ auto ownerEntity = _ownerEntity.lock(); if (!ownerEntity) { return; @@ -101,9 +176,6 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { rigidBody->setAngularVelocity(targetVelocity); } }); - if (!lockResult) { - qDebug() << "ObjectActionSpring::updateActionWorker lock failed"; - } } const float MIN_TIMESCALE = 0.1f; @@ -122,7 +194,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { bool ok = true; positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false); if (!ok) { - positionalTarget = _positionalTarget; + positionalTarget = _desiredPositionalTarget; } ok = true; linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false); @@ -133,7 +205,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { ok = true; rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false); if (!ok) { - rotationalTarget = _rotationalTarget; + rotationalTarget = _desiredRotationalTarget; } ok = true; @@ -144,9 +216,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { } if (somethingChanged || - positionalTarget != _positionalTarget || + positionalTarget != _desiredPositionalTarget || linearTimeScale != _linearTimeScale || - rotationalTarget != _rotationalTarget || + rotationalTarget != _desiredRotationalTarget || angularTimeScale != _angularTimeScale) { // something changed needUpdate = true; @@ -155,9 +227,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { if (needUpdate) { withWriteLock([&] { - _positionalTarget = positionalTarget; + _desiredPositionalTarget = positionalTarget; _linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale)); - _rotationalTarget = rotationalTarget; + _desiredRotationalTarget = rotationalTarget; _angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale)); _active = true; @@ -177,9 +249,9 @@ QVariantMap ObjectActionSpring::getArguments() { QVariantMap arguments = ObjectAction::getArguments(); withReadLock([&] { arguments["linearTimeScale"] = _linearTimeScale; - arguments["targetPosition"] = glmToQMap(_positionalTarget); + arguments["targetPosition"] = glmToQMap(_desiredPositionalTarget); - arguments["targetRotation"] = glmToQMap(_rotationalTarget); + arguments["targetRotation"] = glmToQMap(_desiredRotationalTarget); arguments["angularTimeScale"] = _angularTimeScale; }); return arguments; @@ -194,10 +266,10 @@ QByteArray ObjectActionSpring::serialize() const { dataStream << ObjectActionSpring::springVersion; withReadLock([&] { - dataStream << _positionalTarget; + dataStream << _desiredPositionalTarget; dataStream << _linearTimeScale; dataStream << _positionalTargetSet; - dataStream << _rotationalTarget; + dataStream << _desiredRotationalTarget; dataStream << _angularTimeScale; dataStream << _rotationalTargetSet; dataStream << localTimeToServerTime(_expires); @@ -226,11 +298,11 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) { } withWriteLock([&] { - dataStream >> _positionalTarget; + dataStream >> _desiredPositionalTarget; dataStream >> _linearTimeScale; dataStream >> _positionalTargetSet; - dataStream >> _rotationalTarget; + dataStream >> _desiredRotationalTarget; dataStream >> _angularTimeScale; dataStream >> _rotationalTargetSet; diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index 96bb900bf6..4f9443121e 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -27,16 +27,26 @@ public: virtual QByteArray serialize() const override; virtual void deserialize(QByteArray serializedArguments) override; + virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity); + protected: static const uint16_t springVersion; glm::vec3 _positionalTarget; + glm::vec3 _desiredPositionalTarget; float _linearTimeScale; bool _positionalTargetSet; glm::quat _rotationalTarget; + glm::quat _desiredRotationalTarget; float _angularTimeScale; bool _rotationalTargetSet; + + glm::vec3 _linearVelocityTarget; + glm::vec3 _angularVelocityTarget; + + virtual bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep); }; #endif // hifi_ObjectActionSpring_h diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 2ac07e5c3d..8bbbfcdd88 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ -Script.include("../libraries/utils.js"); +Script.include("/~/system/libraries/utils.js"); // @@ -28,7 +28,7 @@ var WANT_DEBUG_SEARCH_NAME = null; var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab -var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab +var TRIGGER_GRAB_VALUE = 0.75; // Squeezed far enough to complete distant grab var TRIGGER_OFF_VALUE = 0.15; var BUMPER_ON_VALUE = 0.5; From b6918f59a693acdcbc40f9bd15beb604756f413f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 11:33:41 -0700 Subject: [PATCH 10/36] remove extra qualification --- libraries/physics/src/ObjectActionSpring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index 4f9443121e..498bb6c1f5 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -46,7 +46,7 @@ protected: glm::vec3 _linearVelocityTarget; glm::vec3 _angularVelocityTarget; - virtual bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep); + virtual bool prepareForSpringUpdate(btScalar deltaTimeStep); }; #endif // hifi_ObjectActionSpring_h From 382a0c48da96c51a1f66e7533f3cf19bf5f6077e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 12:09:26 -0700 Subject: [PATCH 11/36] fix warning --- libraries/entities/src/EntityTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 27655e2a98..6a0d0c968f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -213,7 +213,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); - properties.setParentID(false); + properties.setParentID(QUuid()); properties.setParentJointIndex(false); if (wantTerseEditLogging()) { From 9db839bc138c3acd01f6ed2b4a4e020772bee8f4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 15:01:00 -0700 Subject: [PATCH 12/36] don't allow someone else to delete an action that I own. reset dynamic property when releasing and entity, even if refCount isn't 0 --- libraries/entities/src/EntityItem.cpp | 7 +++++-- libraries/entities/src/EntityTree.cpp | 4 ++-- libraries/physics/src/ObjectActionSpring.cpp | 6 ++++-- scripts/system/controllers/handControllerGrab.js | 3 ++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7bdd88ae5a..f0022245ad 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1740,6 +1740,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s EntityActionPointer action = _objectActions[actionID]; action->setOwnerEntity(nullptr); + action->setIsMine(false); _objectActions.remove(actionID); if (simulation) { @@ -1846,8 +1847,10 @@ void EntityItem::deserializeActionsInternal() { QUuid id = i.key(); if (!updated.contains(id)) { EntityActionPointer action = i.value(); - // if we've just added this action, don't remove it due to lack of mention in an incoming packet. - if (! action->locallyAddedButNotYetReceived) { + // don't let someone else delete my action. + if (!action->isMine() && + // if we've just added this action, don't remove it due to lack of mention in an incoming packet. + !action->locallyAddedButNotYetReceived) { _actionsToRemove << id; _previouslyDeletedActions.insert(id, now); } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6a0d0c968f..8a3395f9dc 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -213,8 +213,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); - properties.setParentID(QUuid()); - properties.setParentJointIndex(false); + properties.setParentIDChanged(false); + properties.setParentJointIndexChanged(false); if (wantTerseEditLogging()) { qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed"; diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 563733ea2d..49944d6ed9 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -45,10 +45,9 @@ bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm position = _desiredPositionalTarget; linearVelocity = glm::vec3(); angularVelocity = glm::vec3(); - return true; + return true; } - bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { glm::quat rotation; glm::vec3 position; @@ -140,10 +139,13 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); targetVelocity = (-speed / offsetLength) * offset; if (speed > rigidBody->getLinearSleepingThreshold()) { + qDebug() << "HERE"; + forceBodyNonStatic(); rigidBody->activate(); } } // this action is aggresively critically damped and defeats the current velocity + qDebug() << targetVelocity.x() << targetVelocity.y() << targetVelocity.z(); rigidBody->setLinearVelocity(targetVelocity); } diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 8bbbfcdd88..0fdaed58f2 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1895,7 +1895,8 @@ function MyController(hand) { Entities.editEntity(entityID, deactiveProps); } else if (noVelocity) { Entities.editEntity(entityID, {velocity: {x: 0.0, y: 0.0, z: 0.0}, - angularVelocity: {x: 0.0, y: 0.0, z: 0.0}}); + angularVelocity: {x: 0.0, y: 0.0, z: 0.0}, + dynamic: data["dynamic"]}); } } else { data = null; From 91af732516a8613c7f6198dc5ed617bbd534a71b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 16:30:38 -0700 Subject: [PATCH 13/36] if we receive an update from the entity-server that doesn't include one of our actions, resend the action data --- libraries/entities/src/EntityItem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f0022245ad..4bf7aefb7b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1847,6 +1847,12 @@ void EntityItem::deserializeActionsInternal() { QUuid id = i.key(); if (!updated.contains(id)) { EntityActionPointer action = i.value(); + + if (action->isMine()) { + // we just received an update that didn't include one of our actions. tell the server about it. + setActionDataNeedsTransmit(true); + } + // don't let someone else delete my action. if (!action->isMine() && // if we've just added this action, don't remove it due to lack of mention in an incoming packet. From d76b8f23358be65174411253308d967d27226f29 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 May 2016 06:44:52 -0700 Subject: [PATCH 14/36] action->locallyAddedButNotYetReceived is unneeded with isMine available --- libraries/entities/src/EntityActionInterface.h | 2 -- libraries/entities/src/EntityItem.cpp | 14 ++++---------- libraries/physics/src/ObjectActionSpring.cpp | 2 -- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index c634326a31..34de87cca4 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -57,8 +57,6 @@ public: virtual bool isMine() { return _isMine; } virtual void setIsMine(bool value) { _isMine = value; } - bool locallyAddedButNotYetReceived = false; - virtual bool shouldSuppressLocationEdits() { return false; } virtual void prepareForPhysicsSimulation() { } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4bf7aefb7b..908e64708e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1666,7 +1666,7 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act if (!result) { removeActionInternal(action->getID()); } else { - action->locallyAddedButNotYetReceived = true; + action->setIsMine(true); } }); @@ -1821,7 +1821,6 @@ void EntityItem::deserializeActionsInternal() { if (!action->isMine()) { action->deserialize(serializedAction); } - action->locallyAddedButNotYetReceived = false; updated << actionID; } else { auto actionFactory = DependencyManager::get(); @@ -1829,7 +1828,6 @@ void EntityItem::deserializeActionsInternal() { EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { entity->addActionInternal(simulation, action); - action->locallyAddedButNotYetReceived = false; updated << actionID; } else { static QString repeatedMessage = @@ -1849,14 +1847,10 @@ void EntityItem::deserializeActionsInternal() { EntityActionPointer action = i.value(); if (action->isMine()) { - // we just received an update that didn't include one of our actions. tell the server about it. + // we just received an update that didn't include one of our actions. tell the server about it (again). setActionDataNeedsTransmit(true); - } - - // don't let someone else delete my action. - if (!action->isMine() && - // if we've just added this action, don't remove it due to lack of mention in an incoming packet. - !action->locallyAddedButNotYetReceived) { + } else { + // don't let someone else delete my action. _actionsToRemove << id; _previouslyDeletedActions.insert(id, now); } diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 49944d6ed9..22b7ade979 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -139,13 +139,11 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); targetVelocity = (-speed / offsetLength) * offset; if (speed > rigidBody->getLinearSleepingThreshold()) { - qDebug() << "HERE"; forceBodyNonStatic(); rigidBody->activate(); } } // this action is aggresively critically damped and defeats the current velocity - qDebug() << targetVelocity.x() << targetVelocity.y() << targetVelocity.z(); rigidBody->setLinearVelocity(targetVelocity); } From 79c8001d7af967613f49c4bac0e93a78657d9299 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 5 May 2016 11:01:57 -0700 Subject: [PATCH 15/36] Audit thread safety of ResourceCache --- libraries/networking/src/ResourceCache.cpp | 61 +++++++++++++--------- libraries/networking/src/ResourceCache.h | 31 ++++++----- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index c0382a5748..77690a729d 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -40,15 +40,14 @@ void ResourceCacheSharedItems::appendPendingRequest(QWeakPointer resou QList> ResourceCacheSharedItems::getPendingRequests() { QList> result; + Lock lock(_mutex); - { - Lock lock(_mutex); - foreach(QSharedPointer resource, _pendingRequests) { - if (resource) { - result.append(resource); - } + foreach(QSharedPointer resource, _pendingRequests) { + if (resource) { + result.append(resource); } } + return result; } @@ -59,20 +58,20 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const { QList> ResourceCacheSharedItems::getLoadingRequests() { QList> result; + Lock lock(_mutex); - { - Lock lock(_mutex); - foreach(QSharedPointer resource, _loadingRequests) { - if (resource) { - result.append(resource); - } + foreach(QSharedPointer resource, _loadingRequests) { + if (resource) { + result.append(resource); } } + return result; } void ResourceCacheSharedItems::removeRequest(QWeakPointer resource) { Lock lock(_mutex); + // resource can only be removed if it still has a ref-count, as // QWeakPointer has no operator== implementation for two weak ptrs, so // manually loop in case resource has been freed. @@ -88,11 +87,11 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer resource) { } QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { - Lock lock(_mutex); // look for the highest priority pending request int highestIndex = -1; float highestPriority = -FLT_MAX; QSharedPointer highestResource; + Lock lock(_mutex); for (int i = 0; i < _pendingRequests.size();) { // Clear any freed resources @@ -176,12 +175,14 @@ void ResourceCache::refreshAll() { clearUnusedResource(); resetResourceCounters(); - _resourcesLock.lockForRead(); - auto resourcesCopy = _resources; - _resourcesLock.unlock(); + QHash> resources; + { + QReadLocker locker(&_resourcesLock); + resources = _resources; + } // Refresh all remaining resources in use - foreach (QSharedPointer resource, resourcesCopy) { + foreach (QSharedPointer resource, resources) { if (resource) { resource->refresh(); } @@ -231,17 +232,17 @@ void ResourceCache::setRequestLimit(int limit) { void ResourceCache::getResourceAsynchronously(const QUrl& url) { qCDebug(networking) << "ResourceCache::getResourceAsynchronously" << url.toString(); - _resourcesToBeGottenLock.lockForWrite(); + QWriteLocker locker(&_resourcesToBeGottenLock); _resourcesToBeGotten.enqueue(QUrl(url)); - _resourcesToBeGottenLock.unlock(); } void ResourceCache::checkAsynchronousGets() { assert(QThread::currentThread() == thread()); + QWriteLocker locker(&_resourcesToBeGottenLock); if (!_resourcesToBeGotten.isEmpty()) { - _resourcesToBeGottenLock.lockForWrite(); QUrl url = _resourcesToBeGotten.dequeue(); - _resourcesToBeGottenLock.unlock(); + + locker.unlock(); getResource(url); } } @@ -312,8 +313,10 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc if (_unusedResources.contains(resource->getLRUKey())) { _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); + + locker.unlock(); + resetResourceCounters(); } - resetResourceCounters(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -326,7 +329,9 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { it.value()->setCache(nullptr); auto size = it.value()->getBytes(); + locker.unlock(); removeResource(it.value()->getURL(), size); + locker.relock(); _unusedResourcesSize -= size; _unusedResources.erase(it); @@ -346,8 +351,16 @@ void ResourceCache::clearUnusedResource() { } void ResourceCache::resetResourceCounters() { - _numTotalResources = _resources.size(); - _numUnusedResources = _unusedResources.size(); + { + QReadLocker locker(&_resourcesLock); + _numTotalResources = _resources.size(); + } + + { + QReadLocker locker(&_unusedResourcesLock); + _numUnusedResources = _unusedResources.size(); + } + emit dirty(); } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index ed3dbf69b6..a1cffa023f 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -61,6 +61,7 @@ class ResourceCacheSharedItems : public Dependency { using Mutex = std::mutex; using Lock = std::unique_lock; + public: void appendPendingRequest(QWeakPointer newRequest); void appendActiveRequest(QWeakPointer newRequest); @@ -155,26 +156,30 @@ private: void resetResourceCounters(); void removeResource(const QUrl& url, qint64 size = 0); - QReadWriteLock _resourcesLock { QReadWriteLock::Recursive }; - QHash> _resources; - int _lastLRUKey = 0; - + void getResourceAsynchronously(const QUrl& url); + static int _requestLimit; static int _requestsActive; - void getResourceAsynchronously(const QUrl& url); - QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive }; - QQueue _resourcesToBeGotten; - - std::atomic _numTotalResources { 0 }; - std::atomic _numUnusedResources { 0 }; + // Resources + QHash> _resources; + QReadWriteLock _resourcesLock { QReadWriteLock::Recursive }; + int _lastLRUKey = 0; + std::atomic _numTotalResources { 0 }; std::atomic _totalResourcesSize { 0 }; + + // Cached resources + QMap> _unusedResources; + QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive }; + qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; + + std::atomic _numUnusedResources { 0 }; std::atomic _unusedResourcesSize { 0 }; - qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; - QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive }; - QMap> _unusedResources; + // Pending resources + QQueue _resourcesToBeGotten; + QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive }; }; /// Base class for resources. From cd934bab90a2bf639af2915e17c9ddd31b1f4ccb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 May 2016 14:16:13 -0700 Subject: [PATCH 16/36] set _actionDataDirty when adding an action. --- libraries/entities/src/EntityItem.cpp | 21 ++++++++++++++++++--- libraries/entities/src/EntityItem.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8f54273600..deae6bc47b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1705,16 +1705,31 @@ void EntityItem::setPendingOwnershipPriority(quint8 priority, const quint64& tim _simulationOwner.setPendingPriority(priority, timestamp); } +QString EntityItem::actionsToDebugString() { + QString result; + QVector serializedActions; + QHash::const_iterator i = _objectActions.begin(); + while (i != _objectActions.end()) { + const QUuid id = i.key(); + EntityActionPointer action = _objectActions[id]; + EntityActionType actionType = action->getType(); + result += QString("") + actionType + ":" + action->getID().toString() + " "; + i++; + } + return result; +} + bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) { bool result; withWriteLock([&] { checkWaitingToRemove(simulation); result = addActionInternal(simulation, action); - if (!result) { - removeActionInternal(action->getID()); - } else { + if (result) { action->setIsMine(true); + _actionDataDirty = true; + } else { + removeActionInternal(action->getID()); } }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ecb9800e70..64c87bde27 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -378,6 +378,7 @@ public: void grabSimulationOwnership(); void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } + QString actionsToDebugString(); bool addAction(EntitySimulation* simulation, EntityActionPointer action); bool updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments); bool removeAction(EntitySimulation* simulation, const QUuid& actionID); From 96ee33e80e3ec8e5606414ede7e6b9a348daf804 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 15 Apr 2016 14:30:06 -0700 Subject: [PATCH 17/36] Fix avatars collision sounds --- interface/src/avatar/AvatarManager.cpp | 6 +++--- interface/src/avatar/MyAvatar.cpp | 17 +++++++++++++---- interface/src/avatar/MyAvatar.h | 5 +++++ libraries/audio/src/AudioInjector.cpp | 16 ++++------------ libraries/audio/src/AudioInjector.h | 2 +- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 402245d0c3..a1302a934e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -309,8 +309,8 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents // my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.) if (collision.idA.isNull() || collision.idB.isNull()) { MyAvatar* myAvatar = getMyAvatar(); - const QString& collisionSoundURL = myAvatar->getCollisionSoundURL(); - if (!collisionSoundURL.isEmpty()) { + auto collisionSound = myAvatar->getCollisionSound(); + if (collisionSound) { const float velocityChange = glm::length(collision.velocityChange); const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01f; const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION); @@ -327,7 +327,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents // but most avatars are roughly the same size, so let's not be so fancy yet. const float AVATAR_STRETCH_FACTOR = 1.0f; - AudioInjector::playSound(collisionSoundURL, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition()); + AudioInjector::playSound(collisionSound, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition()); myAvatar->collisionWithEntity(collision); return; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bad60643ec..f0e5f2f19e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1232,12 +1232,21 @@ void MyAvatar::clearScriptableSettings() { } void MyAvatar::setCollisionSoundURL(const QString& url) { - _collisionSoundURL = url; - if (!url.isEmpty() && (url != _collisionSoundURL)) { - emit newCollisionSoundURL(QUrl(url)); + if (url != _collisionSoundURL) { + _collisionSoundURL = url; + _collisionSound = DependencyManager::get()->getSound(_collisionSoundURL); + + emit newCollisionSoundURL(QUrl(_collisionSoundURL)); } } +SharedSoundPointer MyAvatar::getCollisionSound() { + if (!_collisionSound) { + _collisionSound = DependencyManager::get()->getSound(_collisionSoundURL); + } + return _collisionSound; +} + void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, const glm::quat& rotation, float scale, bool isSoft, diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fee1a9add3..e72d12ef26 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -16,6 +16,7 @@ #include #include +#include #include @@ -222,6 +223,8 @@ public: const QString& getCollisionSoundURL() { return _collisionSoundURL; } void setCollisionSoundURL(const QString& url); + SharedSoundPointer getCollisionSound(); + void clearScriptableSettings(); float getBoomLength() const { return _boomLength; } @@ -362,6 +365,8 @@ private: quint32 _motionBehaviors; QString _collisionSoundURL; + SharedSoundPointer _collisionSound; + MyCharacterController _characterController; AvatarWeakPointer _lookAtTargetAvatar; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index a6515f5f65..073753c525 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -365,17 +365,9 @@ void AudioInjector::stopAndDeleteLater() { QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); } -AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) { - if (soundUrl.isEmpty()) { - return NULL; - } - auto soundCache = DependencyManager::get(); - if (soundCache.isNull()) { - return NULL; - } - SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl)); - if (sound.isNull() || !sound->isReady()) { - return NULL; +AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position) { + if (!sound || !sound->isReady()) { + return nullptr; } AudioInjectorOptions options; @@ -385,7 +377,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol QByteArray samples = sound->getByteArray(); if (stretchFactor == 1.0f) { - return playSoundAndDelete(samples, options, NULL); + return playSoundAndDelete(samples, options, nullptr); } const int standardRate = AudioConstants::SAMPLE_RATE; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 2dad2856b9..c90256429d 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -60,7 +60,7 @@ public: static AudioInjector* playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface); static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface); - static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position); + static AudioInjector* playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position); public slots: void restart(); From 07adef9465cb3bcc87949bbf236f943920d652b9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 4 May 2016 12:05:53 -0700 Subject: [PATCH 18/36] Fix entities collision sounds --- interface/src/Application.cpp | 15 +++++++++++++-- interface/src/avatar/MyAvatar.cpp | 2 -- interface/src/avatar/MyAvatar.h | 1 + libraries/audio/src/AudioInjector.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 10 +++++----- libraries/entities/src/EntityItem.cpp | 17 +++++++++++++++++ libraries/entities/src/EntityItem.h | 7 ++++++- libraries/entities/src/EntityTree.cpp | 9 ++------- libraries/entities/src/EntityTree.h | 5 +++-- libraries/entities/src/EntityTreeElement.cpp | 2 -- 10 files changed, 48 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2a4088dcc..e3f2812c1f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3019,8 +3019,19 @@ void Application::init() { _entityClipboardRenderer.setTree(_entityClipboard); // Make sure any new sounds are loaded as soon as know about them. - connect(tree.get(), &EntityTree::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); - connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); + connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { + EntityTreePointer tree = getEntities()->getTree(); + if (auto entity = tree->findEntityByEntityItemID(id)) { + auto sound = DependencyManager::get()->getSound(newURL); + entity->setCollisionSound(sound); + } + }, Qt::QueuedConnection); + connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { + if (auto avatar = getMyAvatar()) { + auto sound = DependencyManager::get()->getSound(newURL); + avatar->setCollisionSound(sound); + } + }, Qt::QueuedConnection); } void Application::updateLOD() const { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f0e5f2f19e..f6caedb014 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -97,7 +97,6 @@ MyAvatar::MyAvatar(RigPointer rig) : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), - _collisionSoundURL(""), _characterController(this), _lookAtTargetAvatar(), _shouldRender(true), @@ -1234,7 +1233,6 @@ void MyAvatar::clearScriptableSettings() { void MyAvatar::setCollisionSoundURL(const QString& url) { if (url != _collisionSoundURL) { _collisionSoundURL = url; - _collisionSound = DependencyManager::get()->getSound(_collisionSoundURL); emit newCollisionSoundURL(QUrl(_collisionSoundURL)); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e72d12ef26..d25318c9fb 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -224,6 +224,7 @@ public: void setCollisionSoundURL(const QString& url); SharedSoundPointer getCollisionSound(); + void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; } void clearScriptableSettings(); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 073753c525..878a4c627c 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -395,7 +395,7 @@ AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float vo nInputFrames); Q_UNUSED(nOutputFrames); - return playSoundAndDelete(resampled, options, NULL); + return playSoundAndDelete(resampled, options, nullptr); } AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 013385a169..814faa8874 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -820,14 +820,14 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT return; } - QString collisionSoundURL; + SharedSoundPointer collisionSound; float mass = 1.0; // value doesn't get used, but set it so compiler is quiet AACube minAACube; bool success = false; _tree->withReadLock([&] { EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); if (entity) { - collisionSoundURL = entity->getCollisionSoundURL(); + collisionSound = entity->getCollisionSound(); mass = entity->computeMass(); minAACube = entity->getMinimumAACube(success); } @@ -835,9 +835,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT if (!success) { return; } - if (collisionSoundURL.isEmpty()) { + if (!collisionSound) { return; } + const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity() // The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact, // but that first contact depends on exactly where we hit in the physics step. @@ -859,11 +860,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes. const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE); - // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); - AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position); + AudioInjector::playSound(collisionSound, volume, stretchFactor, position); } void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index bdedbbce77..a36c69b880 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -852,6 +852,23 @@ void EntityItem::setHref(QString value) { _href = value; } +void EntityItem::setCollisionSoundURL(const QString& value) { + if (_collisionSoundURL != value) { + _collisionSoundURL = value; + + if (auto myTree = getTree()) { + myTree->notifyNewCollisionSoundURL(_collisionSoundURL, getEntityItemID()); + } + } +} + +SharedSoundPointer EntityItem::getCollisionSound() { + if (!_collisionSound) { + _collisionSound = DependencyManager::get()->getSound(_collisionSoundURL); + } + return _collisionSound; +} + void EntityItem::simulate(const quint64& now) { if (_lastSimulated == 0) { _lastSimulated = now; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ecb9800e70..210dbba284 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "EntityItemID.h" @@ -250,7 +251,10 @@ public: void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; } const QString& getCollisionSoundURL() const { return _collisionSoundURL; } - void setCollisionSoundURL(const QString& value) { _collisionSoundURL = value; } + void setCollisionSoundURL(const QString& value); + + SharedSoundPointer getCollisionSound(); + void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; } const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity @@ -478,6 +482,7 @@ protected: quint64 _loadedScriptTimestamp{ ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 }; QString _collisionSoundURL; + SharedSoundPointer _collisionSound; glm::vec3 _registrationPoint; float _angularDamping; bool _visible; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b4f0c484d5..7b6756f3c1 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -95,7 +95,6 @@ void EntityTree::postAddEntity(EntityItemPointer entity) { } _isDirty = true; - maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL()); emit addingEntity(entity->getEntityItemID()); // find and hook up any entities with this entity as a (previously) missing parent @@ -223,7 +222,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI QString entityScriptBefore = entity->getScript(); quint64 entityScriptTimestampBefore = entity->getScriptTimestamp(); - QString collisionSoundURLBefore = entity->getCollisionSoundURL(); uint32_t preFlags = entity->getDirtyFlags(); AACube newQueryAACube; @@ -295,7 +293,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI if (entityScriptBefore != entityScriptAfter || reload) { emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed } - maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL()); } // TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG). @@ -362,10 +359,8 @@ void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID, cons emit entityScriptChanging(entityItemID, reload); } -void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisionSoundURL, const QString& nextCollisionSoundURL) { - if (!nextCollisionSoundURL.isEmpty() && (nextCollisionSoundURL != previousCollisionSoundURL)) { - emit newCollisionSoundURL(QUrl(nextCollisionSoundURL)); - } +void EntityTree::notifyNewCollisionSoundURL(const QString& newURL, const EntityItemID& entityID) { + emit newCollisionSoundURL(QUrl(newURL), entityID); } void EntityTree::setSimulation(EntitySimulation* simulation) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 54e516d01d..83bc31aa92 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -249,6 +249,8 @@ public: void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } void deleteDescendantsOfAvatar(QUuid avatarID); + void notifyNewCollisionSoundURL(const QString& newCollisionSoundURL, const EntityItemID& entityID); + public slots: void callLoader(EntityItemID entityID); @@ -256,7 +258,7 @@ signals: void deletingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID); void entityScriptChanging(const EntityItemID& entityItemID, const bool reload); - void newCollisionSoundURL(const QUrl& url); + void newCollisionSoundURL(const QUrl& url, const EntityItemID& entityID); void clearingEntities(); protected: @@ -301,7 +303,6 @@ protected: bool _wantEditLogging = false; bool _wantTerseEditLogging = false; - void maybeNotifyNewCollisionSoundURL(const QString& oldCollisionSoundURL, const QString& newCollisionSoundURL); // some performance tracking properties - only used in server trees diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 8270dc7e69..a919dc4251 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -34,8 +34,6 @@ OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCod return newChild; } - - void EntityTreeElement::init(unsigned char* octalCode) { OctreeElement::init(octalCode); _octreeMemoryUsage += sizeof(EntityTreeElement); From bc6544a3c56dee794fd8e2d3921f94438596e4dd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 5 May 2016 14:46:21 -0700 Subject: [PATCH 19/36] Fix MyAvatar's velocity change --- interface/src/avatar/AvatarManager.cpp | 4 +++- libraries/physics/src/CharacterController.cpp | 12 ++++++++++++ libraries/physics/src/CharacterController.h | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index a1302a934e..e098aac677 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -311,7 +311,9 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents MyAvatar* myAvatar = getMyAvatar(); auto collisionSound = myAvatar->getCollisionSound(); if (collisionSound) { - const float velocityChange = glm::length(collision.velocityChange); + const auto characterController = myAvatar->getCharacterController(); + const float avatarVelocityChange = (characterController ? glm::length(characterController->getVelocityChange()) : 0.0f); + const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange; const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01f; const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f685aee748..6ebe05ba86 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -430,6 +430,14 @@ glm::vec3 CharacterController::getLinearVelocity() const { return velocity; } +glm::vec3 CharacterController::getVelocityChange() const { + glm::vec3 velocity(0.0f); + if (_rigidBody) { + velocity = bulletToGLM(_rigidBody->getLinearVelocity()); + } + return velocity; +} + void CharacterController::preSimulation() { if (_enabled && _dynamicsWorld) { quint64 now = usecTimestampNow(); @@ -437,6 +445,7 @@ void CharacterController::preSimulation() { // slam body to where it is supposed to be _rigidBody->setWorldTransform(_characterBodyTransform); btVector3 velocity = _rigidBody->getLinearVelocity(); + _preSimulationVelocity = velocity; btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp; btVector3 actualHorizVelocity = velocity - actualVertVelocity; @@ -531,6 +540,9 @@ void CharacterController::preSimulation() { void CharacterController::postSimulation() { // postSimulation() exists for symmetry and just in case we need to do something here later + + btVector3 velocity = _rigidBody->getLinearVelocity(); + _velocityChange = velocity - _preSimulationVelocity; } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index d810e904a7..a54ab97a14 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -77,6 +77,7 @@ public: glm::vec3 getFollowVelocity() const; glm::vec3 getLinearVelocity() const; + glm::vec3 getVelocityChange() const; float getCapsuleRadius() const { return _radius; } float getCapsuleHalfHeight() const { return _halfHeight; } @@ -112,6 +113,8 @@ protected: btVector3 _currentUp; btVector3 _targetVelocity; btVector3 _parentVelocity; + btVector3 _preSimulationVelocity; + btVector3 _velocityChange; btTransform _followDesiredBodyTransform; btScalar _followTimeRemaining; btTransform _characterBodyTransform; From cb523a3a715ce41f55aaabc889bf8f786e8bec9a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 May 2016 16:01:05 -0700 Subject: [PATCH 20/36] disable webSurface differently --- .../entities-renderer/src/RenderableWebEntityItem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index ca3f694fd7..891e1dca3b 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -51,11 +51,6 @@ RenderableWebEntityItem::~RenderableWebEntityItem() { } bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { - #ifdef defined(Q_OS_LINUX) - // these don't seem to work on Linux - return false; - #endif - if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) { qWarning() << "Too many concurrent web views to create new view"; return false; @@ -179,9 +174,14 @@ void RenderableWebEntityItem::render(RenderArgs* args) { #endif if (!_webSurface) { + #if defined(Q_OS_LINUX) + // these don't seem to work on Linux + return; + #else if (!buildWebSurface(static_cast(args->_renderer))) { return; } + #endif } _lastRenderTime = usecTimestampNow(); From df2683d989635f296a7f06f15d6a15e28d61fba5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 5 May 2016 16:09:45 -0700 Subject: [PATCH 21/36] Fix compile error --- tests/entities/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/entities/CMakeLists.txt b/tests/entities/CMakeLists.txt index b12771b368..a6ce4cf956 100644 --- a/tests/entities/CMakeLists.txt +++ b/tests/entities/CMakeLists.txt @@ -7,6 +7,6 @@ setup_hifi_project(Network Script) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries -link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation) +link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation audio) package_libraries_for_deployment() From 6a6d6dd20fee85f77e2ed6ccdcfed268cbd44e3d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 5 May 2016 16:34:02 -0700 Subject: [PATCH 22/36] Defer mipmap gen to gpu --- libraries/model/src/model/TextureMap.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 349980b702..0fed0b0b4e 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -171,14 +171,6 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag if (generateMips) { theTexture->autoGenerateMips(-1); - auto levels = theTexture->maxMip(); - uvec2 size(image.width(), image.height()); - for (uint8_t i = 1; i <= levels; ++i) { - size >>= 1; - size = glm::max(size, uvec2(1)); - image = image.scaled(size.x, size.y, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - theTexture->assignStoredMip(i, formatMip, image.byteCount(), image.constBits()); - } } } From 073d845bb5d1e9a22752ff7adfda343593eca01f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 May 2016 18:33:01 -0700 Subject: [PATCH 23/36] show with debug icons when someone else is the simulation owner --- interface/resources/icons/statusIconAtlas.svg | 83 ++++++++++++------- .../src/RenderableEntityItem.cpp | 4 + .../src/RenderableEntityItem.h | 1 + 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/interface/resources/icons/statusIconAtlas.svg b/interface/resources/icons/statusIconAtlas.svg index 72f9bc4af7..027102cc69 100644 --- a/interface/resources/icons/statusIconAtlas.svg +++ b/interface/resources/icons/statusIconAtlas.svg @@ -1,31 +1,52 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 25f4052c75..d148145dde 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -85,10 +85,14 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status: auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID); + bool otherOwnSimulation = !weOwnSimulation && !entity->getSimulationOwner().isNull(); if (weOwnSimulation) { return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE, (unsigned char)RenderItemStatusIcon::SIMULATION_OWNER); + } else if (otherOwnSimulation) { + return render::Item::Status::Value(1.0f, render::Item::Status::Value::RED, + (unsigned char)RenderItemStatusIcon::OTHER_SIMULATION_OWNER); } return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE, (unsigned char)RenderItemStatusIcon::SIMULATION_OWNER); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 92bb98ad32..09451e87d4 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -25,6 +25,7 @@ enum class RenderItemStatusIcon { PACKET_RECEIVED = 2, SIMULATION_OWNER = 3, HAS_ACTIONS = 4, + OTHER_SIMULATION_OWNER = 5, NONE = 255 }; From f80333ee9e010737008896e4dd864a0f301c1cb7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 6 May 2016 10:06:51 -0700 Subject: [PATCH 24/36] fix indentation, move an early exit to earlier --- libraries/physics/src/ObjectActionSpring.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 22b7ade979..e67a681481 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -49,6 +49,11 @@ bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm } bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { + auto ownerEntity = _ownerEntity.lock(); + if (!ownerEntity) { + return false; + } + glm::quat rotation; glm::vec3 position; glm::vec3 linearVelocity; @@ -57,12 +62,7 @@ bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { bool valid = false; int springCount = 0; - auto ownerEntity = _ownerEntity.lock(); - if (!ownerEntity) { - return false; - } - - QList springDerivedActions; + QList springDerivedActions; springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_SPRING)); springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_HOLD)); From 99d35c37db29163013c93c058798703d80150a7f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 6 May 2016 10:42:07 -0700 Subject: [PATCH 25/36] switch OctreeSendThread to use std::this_thread::sleep_for() instead of usleep() --- .../src/octree/OctreeSendThread.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index ec812db8e8..94349bd3bc 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include + #include #include #include @@ -101,13 +104,16 @@ bool OctreeSendThread::process() { int elapsed = (usecTimestampNow() - start); int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed; - if (usecToSleep > 0) { - PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); - usleep(usecToSleep); - } else { + if (usecToSleep <= 0) { const int MIN_USEC_TO_SLEEP = 1; - usleep(MIN_USEC_TO_SLEEP); + usecToSleep = MIN_USEC_TO_SLEEP; } + + { + PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); + std::this_thread::sleep_for(std::chrono::microseconds(usecToSleep)); + } + } return isStillRunning(); // keep running till they terminate us From fe14bc8e52cc0823bb4e475467fbaedc67758251 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 6 May 2016 11:19:27 -0700 Subject: [PATCH 26/36] also switch OctreePersistThread to use std::this_thread::sleep_for() --- libraries/octree/src/OctreePersistThread.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 8169654b0c..d48c35d542 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include + #include #include #include @@ -201,7 +204,7 @@ bool OctreePersistThread::process() { if (isStillRunning()) { quint64 MSECS_TO_USECS = 1000; quint64 USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms - usleep(USECS_TO_SLEEP); + std::this_thread::sleep_for(std::chrono::microseconds(USECS_TO_SLEEP)); // do our updates then check to save... _tree->update(); From 83fad4c52fd27456921ef68f71e9b00e56f27bcd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 6 May 2016 14:19:13 -0700 Subject: [PATCH 27/36] Fix equalities in scriptableResource tests --- scripts/developer/tests/scriptableResource/lib.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/developer/tests/scriptableResource/lib.js b/scripts/developer/tests/scriptableResource/lib.js index 5241d0968e..255b3bd036 100644 --- a/scripts/developer/tests/scriptableResource/lib.js +++ b/scripts/developer/tests/scriptableResource/lib.js @@ -26,8 +26,8 @@ function getFrame(callback) { } function makeFrame(state) { - if (state == Resource.State.FAILED) { throw "Failed to load frame"; } - if (state != Resource.State.FINISHED) { return; } + if (state === Resource.State.FAILED) { throw "Failed to load frame"; } + if (state !== Resource.State.FINISHED) { return; } var pictureFrameProperties = { name: 'scriptableResourceTest Picture Frame', @@ -50,7 +50,6 @@ function getFrame(callback) { position.x += - 5 * Math.sin(rads); position.z += - 5 * Math.cos(rads); - print(JSON.stringify(position)); return position; } } @@ -67,10 +66,10 @@ function prefetch(callback) { var filepath = MOVIE_URL + padded + '.jpg'; var texture = TextureCache.prefetch(filepath); frames.push(texture); - if (!texture.state == Resource.State.FINISHED) { + if (texture.state !== Resource.State.FINISHED) { numLoading++; texture.stateChanged.connect(function(state) { - if (state == Resource.State.FAILED || state == Resource.State.FINISHED) { + if (state === Resource.State.FAILED || state === Resource.State.FINISHED) { --numLoading; if (!numLoading) { callback(frames); } } From eee487723c249bbdfb4872929724f501fe63e642 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 6 May 2016 14:27:07 -0700 Subject: [PATCH 28/36] Fix headers of scriptableResource tests --- scripts/developer/tests/scriptableResource/movieTest.js | 2 +- scripts/developer/tests/scriptableResource/prefetchTest.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/developer/tests/scriptableResource/movieTest.js b/scripts/developer/tests/scriptableResource/movieTest.js index 61b2bf7942..557c53af6a 100644 --- a/scripts/developer/tests/scriptableResource/movieTest.js +++ b/scripts/developer/tests/scriptableResource/movieTest.js @@ -1,5 +1,5 @@ // -// testMovie.js +// movieTest.js // scripts/developer/tests/scriptableResource // // Created by Zach Pomerantz on 4/27/16. diff --git a/scripts/developer/tests/scriptableResource/prefetchTest.js b/scripts/developer/tests/scriptableResource/prefetchTest.js index cda805967e..07acb462cb 100644 --- a/scripts/developer/tests/scriptableResource/prefetchTest.js +++ b/scripts/developer/tests/scriptableResource/prefetchTest.js @@ -1,5 +1,5 @@ // -// testPrefetch.js +// prefetchTest.js // scripts/developer/tests/scriptableResource // // Created by Zach Pomerantz on 4/27/16. From 3f4f10a27e16c3692b598b979583d56ba5db43e9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 6 May 2016 14:25:04 -0700 Subject: [PATCH 29/36] Fix prefetch state changes --- libraries/networking/src/ResourceCache.cpp | 6 +++--- libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 4cc8b1d4f0..16a419d5af 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -139,17 +139,17 @@ void ScriptableResource::setInScript(bool isInScript) { } void ScriptableResource::loadingChanged() { - emit stateChanged(LOADING); + setState(LOADING); } void ScriptableResource::loadedChanged() { - emit stateChanged(LOADED); + setState(LOADED); } void ScriptableResource::finished(bool success) { disconnectHelper(); - emit stateChanged(success ? FINISHED : FAILED); + setState(success ? FINISHED : FAILED); } void ScriptableResource::disconnectHelper() { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index b81c69c079..dd8953a461 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -113,6 +113,9 @@ signals: void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal); void stateChanged(int state); +protected: + void setState(State state) { _state = state; emit stateChanged(_state); } + private slots: void loadingChanged(); void loadedChanged(); From 0fbbbaa985178d35e7649acbf2200552f9ffed6f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 6 May 2016 14:19:53 -0700 Subject: [PATCH 30/36] Add tex loadPerfTest.js --- .../tests/scriptableResource/loadPerfTest.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 scripts/developer/tests/scriptableResource/loadPerfTest.js diff --git a/scripts/developer/tests/scriptableResource/loadPerfTest.js b/scripts/developer/tests/scriptableResource/loadPerfTest.js new file mode 100644 index 0000000000..17feef264d --- /dev/null +++ b/scripts/developer/tests/scriptableResource/loadPerfTest.js @@ -0,0 +1,34 @@ +// +// loadPerfTest.js +// scripts/developer/tests/scriptableResource +// +// Created by Zach Pomerantz on 4/27/16. +// Copyright 2016 High Fidelity, Inc. +// +// Preloads 158 textures 50 times for performance profiling. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var TIMES = 50; + +Script.include([ + '../../../developer/utilities/cache/cacheStats.js', + 'lib.js', +], function() { + var fetch = function() { + prefetch(function(frames) { + while (frames.length) { frames.pop(); } + Script.requestGarbageCollection(); + + if (--TIMES > 0) { + // Pause a bit to avoid a deadlock + var DEADLOCK_AVOIDANCE_TIMEOUT = 100; + Script.setTimeout(fetch, DEADLOCK_AVOIDANCE_TIMEOUT); + } + }); + }; + + fetch(); +}); From da75c271881a1b1d742b8357fa28094efe356e1e Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 6 May 2016 18:57:19 -0700 Subject: [PATCH 31/36] fixing bad color format assignment code and bad color format for the cubemaps --- libraries/model/src/model/TextureMap.cpp | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 349980b702..a8428233a3 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -105,19 +105,19 @@ const QImage& image, bool isLinear, bool doCompress) { gpu::Semantic gpuSemantic; gpu::Semantic mipSemantic; if (isLinear) { - mipSemantic = gpu::SBGRA; - if (doCompress) { - gpuSemantic = gpu::COMPRESSED_SRGBA; - } else { - gpuSemantic = gpu::SRGBA; - } - } else { mipSemantic = gpu::BGRA; if (doCompress) { gpuSemantic = gpu::COMPRESSED_RGBA; } else { gpuSemantic = gpu::RGBA; } + } else { + mipSemantic = gpu::SBGRA; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_SRGBA; + } else { + gpuSemantic = gpu::SRGBA; + } } formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpuSemantic); formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic); @@ -125,19 +125,19 @@ const QImage& image, bool isLinear, bool doCompress) { gpu::Semantic gpuSemantic; gpu::Semantic mipSemantic; if (isLinear) { - mipSemantic = gpu::SRGB; - if (doCompress) { - gpuSemantic = gpu::COMPRESSED_SRGB; - } else { - gpuSemantic = gpu::SRGB; - } - } else { mipSemantic = gpu::RGB; if (doCompress) { gpuSemantic = gpu::COMPRESSED_RGB; } else { gpuSemantic = gpu::RGB; } + } else { + mipSemantic = gpu::SRGB; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_SRGB; + } else { + gpuSemantic = gpu::SRGB; + } } formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic); formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic); @@ -186,20 +186,20 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag } gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, false, true); + return process2DTextureColorFromImage(srcImage, false, false, true); } gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, true, true); + return process2DTextureColorFromImage(srcImage, false, true, true); } gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, true, true); + return process2DTextureColorFromImage(srcImage, false, true, true); } gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, true, true); + return process2DTextureColorFromImage(srcImage, false, true, true); } From 173d2a590c4bf265b441824754848590ffdd7480 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 6 May 2016 18:19:10 -0700 Subject: [PATCH 32/36] Use sleep_until for ScriptEngine --- assignment-client/src/Agent.cpp | 3 +- libraries/script-engine/src/ScriptEngine.cpp | 38 ++++++++++++++++---- libraries/script-engine/src/ScriptEngine.h | 4 +-- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ef20dc82e2..f8f0f7904a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -386,8 +386,7 @@ void Agent::sendAvatarBillboardPacket() { void Agent::processAgentAvatarAndAudio(float deltaTime) { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); - const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE) - / (1000 * 1000)) + 0.5); + const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / SCRIPT_FPS + 0.5; const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 6c7739c784..464b514fd5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include + #include #include #include @@ -706,9 +709,15 @@ void ScriptEngine::run() { QScriptValue result = evaluate(_scriptContents, _fileNameString); - QElapsedTimer startTime; - startTime.start(); +#ifdef _WIN32 + // VS13 does not sleep_until unless it uses the system_clock, see: + // https://www.reddit.com/r/cpp_questions/comments/3o71ic/sleep_until_not_working_with_a_time_pointsteady/ + using clock = std::chrono::system_clock; +#else + using clock = std::chrono::high_resolution_clock; +#endif + clock::time_point startTime = clock::now(); int thisFrame = 0; auto nodeList = DependencyManager::get(); @@ -716,12 +725,29 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); + // TODO: Integrate this with signals/slots instead of this busy wait while (!_isFinished) { - int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec - if (usecToSleep > 0) { - usleep(usecToSleep); - } + // Throttle to SCRIPT_FPS + const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); + clock::time_point sleepTime(startTime + thisFrame++ * FRAME_DURATION); + std::this_thread::sleep_until(sleepTime); +#ifdef SCRIPT_DELAY_DEBUG + { + auto now = clock::now(); + uint64_t seconds = std::chrono::duration_cast(now - startTime).count(); + if (seconds > 0) { // avoid division by zero and time travel + uint64_t fps = thisFrame / seconds; + // Overreporting artificially reduces the reported rate + if (thisFrame % SCRIPT_FPS == 0) { + qCDebug(scriptengine) << + "Frame:" << thisFrame << + "Slept (us):" << std::chrono::duration_cast(now - sleepTime).count() << + "FPS:" << fps; + } + } + } +#endif if (_isFinished) { break; } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 175a3f1f1c..f050997235 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -39,9 +39,9 @@ #include "ScriptUUID.h" #include "Vec3.h" -const QString NO_SCRIPT(""); +static const QString NO_SCRIPT(""); -const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); +static const int SCRIPT_FPS = 60; class CallbackData { public: From f8f86a0d451b991846dc3796398d36799df06e1d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 May 2016 11:05:38 -0700 Subject: [PATCH 33/36] only _exit if not DEBUG --- interface/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index bf1fe1d922..1726d47045 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -203,7 +203,7 @@ int main(int argc, const char* argv[]) { Application::shutdownPlugins(); qCDebug(interfaceapp, "Normal exit."); -#if defined(DEBUG) && !defined(Q_OS_LINUX) +#if !defined(DEBUG) && !defined(Q_OS_LINUX) // HACK: exit immediately (don't handle shutdown callbacks) for Release build _exit(exitCode); #endif From 0f768b13b9a61c10ead0dc072a3ca08fbf3a024a Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Sat, 7 May 2016 18:42:43 -0700 Subject: [PATCH 34/36] Working on OSX Rift functionality --- .../display-plugins/OpenGLDisplayPlugin.cpp | 18 +-- .../src/display-plugins/OpenGLDisplayPlugin.h | 1 + .../display-plugins/hmd/HmdDisplayPlugin.cpp | 21 ++-- libraries/gl/src/gl/QOpenGLContextWrapper.cpp | 13 ++- libraries/gl/src/gl/QOpenGLContextWrapper.h | 3 + plugins/oculusLegacy/CMakeLists.txt | 8 +- .../src/OculusLegacyDisplayPlugin.cpp | 104 ++++++++++++++---- .../src/OculusLegacyDisplayPlugin.h | 31 +++--- 8 files changed, 144 insertions(+), 55 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 7d4eebb7a2..a0b6ae3939 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -237,12 +237,6 @@ bool OpenGLDisplayPlugin::activate() { _vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported(); - // Child classes may override this in order to do things like initialize - // libraries, etc - if (!internalActivate()) { - return false; - } - #if THREADED_PRESENT // Start the present thread if necessary @@ -258,8 +252,18 @@ bool OpenGLDisplayPlugin::activate() { // Start execution presentThread->start(); } + _presentThread = presentThread.data(); +#endif + + // Child classes may override this in order to do things like initialize + // libraries, etc + if (!internalActivate()) { + return false; + } - // This should not return until the new context has been customized +#if THREADED_PRESENT + + // This should not return until the new context has been customized // and the old context (if any) has been uncustomized presentThread->setNewDisplayPlugin(this); #else diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index defa57fc58..c87ff1bc93 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -103,6 +103,7 @@ protected: virtual void updateFrameData(); + QThread* _presentThread{ nullptr }; ProgramPtr _program; int32_t _mvpUniform { -1 }; int32_t _alphaUniform { -1 }; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 79b50a7f88..372337ae4d 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -63,7 +63,7 @@ bool HmdDisplayPlugin::internalActivate() { } -static const char * REPROJECTION_VS = R"VS(#version 450 core +static const char * REPROJECTION_VS = R"VS(#version 410 core in vec3 Position; in vec2 TexCoord; @@ -78,15 +78,15 @@ void main() { )VS"; -static const GLint REPROJECTION_MATRIX_LOCATION = 0; -static const GLint INVERSE_PROJECTION_MATRIX_LOCATION = 4; -static const GLint PROJECTION_MATRIX_LOCATION = 12; -static const char * REPROJECTION_FS = R"FS(#version 450 core +static GLint REPROJECTION_MATRIX_LOCATION = -1; +static GLint INVERSE_PROJECTION_MATRIX_LOCATION = -1; +static GLint PROJECTION_MATRIX_LOCATION = -1; +static const char * REPROJECTION_FS = R"FS(#version 410 core uniform sampler2D sampler; -layout (location = 0) uniform mat3 reprojection = mat3(1); -layout (location = 4) uniform mat4 inverseProjections[2]; -layout (location = 12) uniform mat4 projections[2]; +uniform mat3 reprojection = mat3(1); +uniform mat4 inverseProjections[2]; +uniform mat4 projections[2]; in vec2 vTexCoord; in vec3 vPosition; @@ -205,6 +205,11 @@ void HmdDisplayPlugin::customizeContext() { _enablePreview = !isVsyncEnabled(); _sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO); compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS); + + using namespace oglplus; + REPROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "reprojection").Location(); + INVERSE_PROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "inverseProjections").Location(); + PROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "projections").Location(); } void HmdDisplayPlugin::uncustomizeContext() { diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 185fdaf7f4..8c9a1ba113 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -17,8 +17,15 @@ QOpenGLContext* QOpenGLContextWrapper::currentContext() { return QOpenGLContext::currentContext(); } + QOpenGLContextWrapper::QOpenGLContextWrapper() : - _context(new QOpenGLContext) +_context(new QOpenGLContext) +{ +} + + +QOpenGLContextWrapper::QOpenGLContextWrapper(QOpenGLContext* context) : + _context(context) { } @@ -50,3 +57,7 @@ bool isCurrentContext(QOpenGLContext* context) { return QOpenGLContext::currentContext() == context; } +void QOpenGLContextWrapper::moveToThread(QThread* thread) { + _context->moveToThread(thread); +} + diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.h b/libraries/gl/src/gl/QOpenGLContextWrapper.h index 09f1d67280..33cc0b25e9 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.h +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.h @@ -15,16 +15,19 @@ class QOpenGLContext; class QSurface; class QSurfaceFormat; +class QThread; class QOpenGLContextWrapper { public: QOpenGLContextWrapper(); + QOpenGLContextWrapper(QOpenGLContext* context); void setFormat(const QSurfaceFormat& format); bool create(); void swapBuffers(QSurface* surface); bool makeCurrent(QSurface* surface); void doneCurrent(); void setShareContext(QOpenGLContext* otherContext); + void moveToThread(QThread* thread); static QOpenGLContext* currentContext(); diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt index 9e97b3791c..a4e00013f1 100644 --- a/plugins/oculusLegacy/CMakeLists.txt +++ b/plugins/oculusLegacy/CMakeLists.txt @@ -12,13 +12,17 @@ if (APPLE) set(TARGET_NAME oculusLegacy) setup_hifi_plugin() - link_hifi_libraries(shared gl gpu plugins display-plugins input-plugins) + link_hifi_libraries(shared gl gpu plugins ui display-plugins input-plugins) include_hifi_library_headers(octree) add_dependency_external_projects(LibOVR) find_package(LibOVR REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) + find_library(COCOA_LIBRARY Cocoa) + find_library(IOKIT_LIBRARY IOKit) + target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES} ${COCOA_LIBRARY} ${IOKIT_LIBRARY}) + + endif() diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 34e36d6a6b..6ceddec11b 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -16,7 +17,12 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -39,7 +45,7 @@ void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo = FrameInfo(); _currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _trackingState = ovrHmd_GetTrackingState(_hmd, _currentRenderFrameInfo.predictedDisplayTime); - _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose); + _currentRenderFrameInfo.rawRenderPose = _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose); Lock lock(_mutex); _frameInfos[frameIndex] = _currentRenderFrameInfo; } @@ -72,14 +78,34 @@ bool OculusLegacyDisplayPlugin::isSupported() const { } bool OculusLegacyDisplayPlugin::internalActivate() { - Parent::internalActivate(); - + if (!Parent::internalActivate()) { + return false; + } + if (!(ovr_Initialize(nullptr))) { Q_ASSERT(false); qFatal("Failed to Initialize SDK"); return false; } + + _hmdWindow = new GLWindow(); + _hmdWindow->create(); + _hmdWindow->createContext(_container->getPrimaryContext()); + auto hmdScreen = qApp->screens()[_hmdScreen]; + auto hmdGeometry = hmdScreen->geometry(); + _hmdWindow->setGeometry(hmdGeometry); + _hmdWindow->showFullScreen(); + + _hmdWindow->makeCurrent(); + glClearColor(1, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + _hmdWindow->swapBuffers(); + + _container->makeRenderingContextCurrent(); + + QOpenGLContextWrapper(_hmdWindow->context()).moveToThread(_presentThread); + _hswDismissed = false; _hmd = ovrHmd_Create(0); if (!_hmd) { @@ -96,7 +122,8 @@ bool OculusLegacyDisplayPlugin::internalActivate() { ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded); _eyeProjections[eye] = toGlm(ovrPerspectiveProjection); - _eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeViewOffset)); + _ovrEyeOffsets[eye] = erd.HmdToEyeViewOffset; + _eyeOffsets[eye] = glm::translate(mat4(), -1.0f * toGlm(_ovrEyeOffsets[eye])); eyeSizes[eye] = toGlm(ovrHmd_GetFovTextureSize(_hmd, eye, erd.Fov, 1.0f)); }); @@ -121,6 +148,11 @@ void OculusLegacyDisplayPlugin::internalDeactivate() { ovrHmd_Destroy(_hmd); _hmd = nullptr; ovr_Shutdown(); + _hmdWindow->showNormal(); + _hmdWindow->destroy(); + _hmdWindow->deleteLater(); + _hmdWindow = nullptr; + _container->makeRenderingContextCurrent(); } // DLL based display plugins MUST initialize GLEW inside the DLL code. @@ -131,20 +163,21 @@ void OculusLegacyDisplayPlugin::customizeContext() { glewInit(); glGetError(); }); + _hmdWindow->requestActivate(); + QThread::msleep(1000); Parent::customizeContext(); -#if 0 ovrGLConfig config; memset(&config, 0, sizeof(ovrRenderAPIConfig)); auto& header = config.Config.Header; header.API = ovrRenderAPI_OpenGL; header.BackBufferSize = _hmd->Resolution; header.Multisample = 1; - int distortionCaps = ovrDistortionCap_TimeWarp; + int distortionCaps = ovrDistortionCap_TimeWarp | ovrDistortionCap_Vignette; memset(_eyeTextures, 0, sizeof(ovrTexture) * 2); ovr_for_each_eye([&](ovrEyeType eye) { auto& header = _eyeTextures[eye].Header; header.API = ovrRenderAPI_OpenGL; - header.TextureSize = { (int)_desiredFramebufferSize.x, (int)_desiredFramebufferSize.y }; + header.TextureSize = { (int)_renderTargetSize.x, (int)_renderTargetSize.y }; header.RenderViewport.Size = header.TextureSize; header.RenderViewport.Size.w /= 2; if (eye == ovrEye_Right) { @@ -152,29 +185,57 @@ void OculusLegacyDisplayPlugin::customizeContext() { } }); + if (_hmdWindow->makeCurrent()) { #ifndef NDEBUG - ovrBool result = -#endif - ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); - assert(result); + ovrBool result = #endif + ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); + assert(result); + _hmdWindow->doneCurrent(); + } + } -#if 0 void OculusLegacyDisplayPlugin::uncustomizeContext() { - HmdDisplayPlugin::uncustomizeContext(); + _hmdWindow->doneCurrent(); + QOpenGLContextWrapper(_hmdWindow->context()).moveToThread(qApp->thread()); + Parent::uncustomizeContext(); } -void OculusLegacyDisplayPlugin::internalPresent() { - ovrHmd_BeginFrame(_hmd, 0); - ovr_for_each_eye([&](ovrEyeType eye) { - reinterpret_cast(_eyeTextures[eye]).OGL.TexId = _currentSceneTexture; - }); - ovrHmd_EndFrame(_hmd, _eyePoses, _eyeTextures); -} +void OculusLegacyDisplayPlugin::hmdPresent() { + if (!_hswDismissed) { + ovrHSWDisplayState hswState; + ovrHmd_GetHSWDisplayState(_hmd, &hswState); + if (hswState.Displayed) { + ovrHmd_DismissHSWDisplay(_hmd); + } -#endif + } + auto r = glm::quat_cast(_currentPresentFrameInfo.presentPose); + ovrQuatf ovrRotation = { r.x, r.y, r.z, r.w }; + ovrPosef eyePoses[2]; + memset(eyePoses, 0, sizeof(ovrPosef) * 2); + eyePoses[0].Orientation = eyePoses[1].Orientation = ovrRotation; + + GLint texture = oglplus::GetName(_compositeFramebuffer->color); + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + if (_hmdWindow->makeCurrent()) { + glClearColor(0, 0.4, 0.8, 1); + glClear(GL_COLOR_BUFFER_BIT); + ovrHmd_BeginFrame(_hmd, _currentPresentFrameIndex); + glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(sync); + ovr_for_each_eye([&](ovrEyeType eye) { + reinterpret_cast(_eyeTextures[eye]).OGL.TexId = texture; + }); + ovrHmd_EndFrame(_hmd, eyePoses, _eyeTextures); + _hmdWindow->doneCurrent(); + } + static auto widget = _container->getPrimaryWidget(); + widget->makeCurrent(); +} int OculusLegacyDisplayPlugin::getHmdScreen() const { return _hmdScreen; @@ -184,4 +245,3 @@ float OculusLegacyDisplayPlugin::getTargetFrameRate() const { return TARGET_RATE_OculusLegacy; } - diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index bebf3fa2c7..5900ad4c58 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -14,42 +14,43 @@ #include const float TARGET_RATE_OculusLegacy = 75.0f; +class GLWindow; class OculusLegacyDisplayPlugin : public HmdDisplayPlugin { using Parent = HmdDisplayPlugin; public: OculusLegacyDisplayPlugin(); - virtual bool isSupported() const override; - virtual const QString& getName() const override { return NAME; } + bool isSupported() const override; + const QString& getName() const override { return NAME; } - virtual int getHmdScreen() const override; + int getHmdScreen() const override; // Stereo specific methods - virtual void resetSensors() override; - virtual void beginFrameRender(uint32_t frameIndex) override; + void resetSensors() override; + void beginFrameRender(uint32_t frameIndex) override; - virtual float getTargetFrameRate() const override; + float getTargetFrameRate() const override; protected: - virtual bool internalActivate() override; - virtual void internalDeactivate() override; + bool internalActivate() override; + void internalDeactivate() override; - virtual void customizeContext() override; - void hmdPresent() override {} + void customizeContext() override; + void uncustomizeContext() override; + void hmdPresent() override; bool isHmdMounted() const override { return true; } -#if 0 - virtual void uncustomizeContext() override; - virtual void internalPresent() override; -#endif private: static const QString NAME; + GLWindow* _hmdWindow{ nullptr }; ovrHmd _hmd; mutable ovrTrackingState _trackingState; ovrEyeRenderDesc _eyeRenderDescs[2]; + ovrVector3f _ovrEyeOffsets[2]; + ovrFovPort _eyeFovs[2]; - //ovrTexture _eyeTextures[2]; // FIXME - not currently in use + ovrTexture _eyeTextures[2]; // FIXME - not currently in use mutable int _hmdScreen { -1 }; bool _hswDismissed { false }; }; From 335841bf0f2ddb9ad614fd0d34c011ebb9d89a94 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 8 May 2016 23:35:18 -0700 Subject: [PATCH 35/36] Fix plugin loading on OSX --- libraries/plugins/src/plugins/PluginManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 4429f49346..936cb8a7ee 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -32,7 +32,11 @@ const LoaderList& getLoadedPlugins() { static std::once_flag once; static LoaderList loadedPlugins; std::call_once(once, [&] { +#ifdef Q_OS_MAC + QString pluginPath = QCoreApplication::applicationDirPath() + "/../PlugIns/"; +#else QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/"; +#endif QDir pluginDir(pluginPath); pluginDir.setFilter(QDir::Files); if (pluginDir.exists()) { From 7db082b91567c06602b068511f9f55e6912cae50 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 9 May 2016 15:05:13 -0700 Subject: [PATCH 36/36] Amend comment that was not a busy wait --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 464b514fd5..63bbd142e1 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -725,7 +725,7 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); - // TODO: Integrate this with signals/slots instead of this busy wait + // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine while (!_isFinished) { // Throttle to SCRIPT_FPS const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1);