From d320f5b6f4e2f616501107c627cc3081300e035e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 14:40:12 -0700 Subject: [PATCH 01/56] remember uuid of deleted actions for 20 seconds and don't re-add them --- libraries/entities/src/EntityItem.cpp | 20 +++++++++++++++++--- libraries/entities/src/EntityItem.h | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ce719ee976..161d2c9005 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -34,7 +34,7 @@ bool EntityItem::_sendPhysicsUpdates = true; int EntityItem::_maxActionsDataSize = 800; - +quint64 EntityItem::_rememberDeletedActionTime = 20; // seconds EntityItem::EntityItem(const EntityItemID& entityItemID) : _type(EntityTypes::Unknown), _id(entityItemID), @@ -1618,6 +1618,8 @@ void EntityItem::deserializeActions() { void EntityItem::deserializeActionsInternal() { assertWriteLocked(); + quint64 now = usecTimestampNow(); + if (!_element) { return; } @@ -1643,6 +1645,10 @@ void EntityItem::deserializeActionsInternal() { QUuid actionID; serializedActionStream >> actionType; serializedActionStream >> actionID; + if (_previouslyDeletedActions.contains(actionID)) { + continue; + } + updated << actionID; if (_objectActions.contains(actionID)) { @@ -1652,8 +1658,6 @@ void EntityItem::deserializeActionsInternal() { action->deserialize(serializedAction); } else { auto actionFactory = DependencyManager::get(); - - // EntityItemPointer entity = entityTree->findEntityByEntityItemID(_id, false); EntityItemPointer entity = shared_from_this(); EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { @@ -1668,10 +1672,20 @@ void EntityItem::deserializeActionsInternal() { QUuid id = i.key(); if (!updated.contains(id)) { _actionsToRemove << id; + _previouslyDeletedActions.insert(id, now); } i++; } + // trim down _previouslyDeletedActions + QMutableHashIterator _previouslyDeletedIter(_previouslyDeletedActions); + while (_previouslyDeletedIter.hasNext()) { + _previouslyDeletedIter.next(); + if (_previouslyDeletedIter.value() - now > _rememberDeletedActionTime) { + _previouslyDeletedActions.remove(_previouslyDeletedIter.key()); + } + } + return; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 62b436b498..7f760bcf33 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -519,6 +519,9 @@ protected: void checkWaitingToRemove(EntitySimulation* simulation = nullptr); mutable QSet _actionsToRemove; mutable bool _actionDataDirty = false; + // _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag + static quint64 _rememberDeletedActionTime; + mutable QHash _previouslyDeletedActions; }; #endif // hifi_EntityItem_h From 56b50b5fb302d5d889e6b4317b615c70e7ac9d51 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 14:45:10 -0700 Subject: [PATCH 02/56] also add action to _previouslyDeletedActions if the local interface deletes the action --- libraries/entities/src/EntityItem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 161d2c9005..acd2e7d316 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1566,6 +1566,7 @@ bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionI bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) { assertWriteLocked(); + _previouslyDeletedActions.insert(actionID, usecTimestampNow()); if (_objectActions.contains(actionID)) { if (!simulation) { EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; From fa7a5f1a615e599f6f7e7e8cbe9878a67b5c464c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 14:51:33 -0700 Subject: [PATCH 03/56] formatting, fix a bug --- libraries/entities/src/EntityItem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index acd2e7d316..1ecaf238b2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -35,6 +35,7 @@ bool EntityItem::_sendPhysicsUpdates = true; int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20; // seconds + EntityItem::EntityItem(const EntityItemID& entityItemID) : _type(EntityTypes::Unknown), _id(entityItemID), @@ -1682,7 +1683,7 @@ void EntityItem::deserializeActionsInternal() { QMutableHashIterator _previouslyDeletedIter(_previouslyDeletedActions); while (_previouslyDeletedIter.hasNext()) { _previouslyDeletedIter.next(); - if (_previouslyDeletedIter.value() - now > _rememberDeletedActionTime) { + if (now - _previouslyDeletedIter.value() > _rememberDeletedActionTime) { _previouslyDeletedActions.remove(_previouslyDeletedIter.key()); } } From f2ebba9863a077cff9a008eb98082e470be41c79 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 16:16:23 -0700 Subject: [PATCH 04/56] separate out the inbound and outbound caches of serialized action data --- libraries/entities/src/EntityItem.cpp | 28 ++++++++++++++++----------- libraries/entities/src/EntityItem.h | 4 +++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1ecaf238b2..1bb70be205 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -34,7 +34,7 @@ bool EntityItem::_sendPhysicsUpdates = true; int EntityItem::_maxActionsDataSize = 800; -quint64 EntityItem::_rememberDeletedActionTime = 20; // seconds +quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; EntityItem::EntityItem(const EntityItemID& entityItemID) : _type(EntityTypes::Unknown), @@ -1528,7 +1528,7 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi bool success; QByteArray newDataCache = serializeActions(success); if (success) { - _allActionsDataCache = newDataCache; + _allActionsDataCacheOut = newDataCache; _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } return success; @@ -1547,7 +1547,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI success = action->updateArguments(arguments); if (success) { - _allActionsDataCache = serializeActions(success); + _allActionsDataCacheOut = serializeActions(success); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } else { qDebug() << "EntityItem::updateAction failed"; @@ -1583,7 +1583,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s } bool success = true; - _allActionsDataCache = serializeActions(success); + _allActionsDataCacheOut = serializeActions(success); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; return success; } @@ -1602,8 +1602,10 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { } // empty _serializedActions means no actions for the EntityItem _actionsToRemove.clear(); - _allActionsDataCache.clear(); + _allActionsDataCacheIn.clear(); + _allActionsDataCacheOut.clear(); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; + _actionDataDirty = true; }); return true; } @@ -1634,8 +1636,8 @@ void EntityItem::deserializeActionsInternal() { assert(simulation); QVector serializedActions; - if (_allActionsDataCache.size() > 0) { - QDataStream serializedActionsStream(_allActionsDataCache); + if (_allActionsDataCacheIn.size() > 0) { + QDataStream serializedActionsStream(_allActionsDataCacheIn); serializedActionsStream >> serializedActions; } @@ -1688,6 +1690,8 @@ void EntityItem::deserializeActionsInternal() { } } + _actionDataDirty = true; + return; } @@ -1709,8 +1713,10 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { assertWriteLocked(); checkWaitingToRemove(); - _allActionsDataCache = actionData; - deserializeActionsInternal(); + if (_allActionsDataCacheIn != actionData) { + _allActionsDataCacheIn = actionData; + deserializeActionsInternal(); + } } QByteArray EntityItem::serializeActions(bool& success) const { @@ -1749,11 +1755,11 @@ const QByteArray EntityItem::getActionDataInternal() const { bool success; QByteArray newDataCache = serializeActions(success); if (success) { - _allActionsDataCache = newDataCache; + _allActionsDataCacheOut = newDataCache; } _actionDataDirty = false; } - return _allActionsDataCache; + return _allActionsDataCacheOut; } const QByteArray EntityItem::getActionData() const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7f760bcf33..b48da7cdff 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -512,7 +512,9 @@ protected: QHash _objectActions; static int _maxActionsDataSize; - mutable QByteArray _allActionsDataCache; + mutable QByteArray _allActionsDataCacheIn; + mutable QByteArray _allActionsDataCacheOut; + // when an entity-server starts up, EntityItem::setActionData is called before the entity-tree is // ready. This means we can't find our EntityItemPointer or add the action to the simulation. These // are used to keep track of and work around this situation. From e90b156b7bd7c8456e6a6376cdf0db8f861a6c2f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 17:02:02 -0700 Subject: [PATCH 05/56] avoid: add an action, immediately receive an update to that entities action, delete the just-added action because it wasn't in the packet --- libraries/entities/src/EntityActionInterface.h | 2 ++ libraries/entities/src/EntityItem.cpp | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index e61019c98c..4432b26a6a 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -48,6 +48,8 @@ public: virtual bool lifetimeIsOver() { return false; } + bool locallyAddedButNotYetReceived = false; + protected: virtual glm::vec3 getPosition() = 0; virtual void setPosition(glm::vec3 position) = 0; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1bb70be205..5bcb61963c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1506,6 +1506,8 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act result = addActionInternal(simulation, action); if (!result) { removeActionInternal(action->getID()); + } else { + action->locallyAddedButNotYetReceived = true; } }); @@ -1665,6 +1667,7 @@ void EntityItem::deserializeActionsInternal() { EntityItemPointer entity = shared_from_this(); EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { + action->locallyAddedButNotYetReceived = false; entity->addActionInternal(simulation, action); } } @@ -1675,8 +1678,12 @@ void EntityItem::deserializeActionsInternal() { while (i != _objectActions.end()) { QUuid id = i.key(); if (!updated.contains(id)) { - _actionsToRemove << id; - _previouslyDeletedActions.insert(id, now); + 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) { + _actionsToRemove << id; + _previouslyDeletedActions.insert(id, now); + } } i++; } From 40c5103d2fba7b3cbd2cc047cd002086651d6a1c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 17:15:20 -0700 Subject: [PATCH 06/56] back out change where actino data caches were split into in/out --- libraries/entities/src/EntityItem.cpp | 21 ++++++++++----------- libraries/entities/src/EntityItem.h | 3 +-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5bcb61963c..2c18ac5cfd 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1530,7 +1530,7 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi bool success; QByteArray newDataCache = serializeActions(success); if (success) { - _allActionsDataCacheOut = newDataCache; + _allActionsDataCache = newDataCache; _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } return success; @@ -1549,7 +1549,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI success = action->updateArguments(arguments); if (success) { - _allActionsDataCacheOut = serializeActions(success); + _allActionsDataCache = serializeActions(success); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } else { qDebug() << "EntityItem::updateAction failed"; @@ -1585,7 +1585,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s } bool success = true; - _allActionsDataCacheOut = serializeActions(success); + _allActionsDataCache = serializeActions(success); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; return success; } @@ -1604,8 +1604,7 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { } // empty _serializedActions means no actions for the EntityItem _actionsToRemove.clear(); - _allActionsDataCacheIn.clear(); - _allActionsDataCacheOut.clear(); + _allActionsDataCache.clear(); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; _actionDataDirty = true; }); @@ -1638,8 +1637,8 @@ void EntityItem::deserializeActionsInternal() { assert(simulation); QVector serializedActions; - if (_allActionsDataCacheIn.size() > 0) { - QDataStream serializedActionsStream(_allActionsDataCacheIn); + if (_allActionsDataCache.size() > 0) { + QDataStream serializedActionsStream(_allActionsDataCache); serializedActionsStream >> serializedActions; } @@ -1720,8 +1719,8 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { assertWriteLocked(); checkWaitingToRemove(); - if (_allActionsDataCacheIn != actionData) { - _allActionsDataCacheIn = actionData; + if (_allActionsDataCache != actionData) { + _allActionsDataCache = actionData; deserializeActionsInternal(); } } @@ -1762,11 +1761,11 @@ const QByteArray EntityItem::getActionDataInternal() const { bool success; QByteArray newDataCache = serializeActions(success); if (success) { - _allActionsDataCacheOut = newDataCache; + _allActionsDataCache = newDataCache; } _actionDataDirty = false; } - return _allActionsDataCacheOut; + return _allActionsDataCache; } const QByteArray EntityItem::getActionData() const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b48da7cdff..c856794322 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -512,8 +512,7 @@ protected: QHash _objectActions; static int _maxActionsDataSize; - mutable QByteArray _allActionsDataCacheIn; - mutable QByteArray _allActionsDataCacheOut; + mutable QByteArray _allActionsDataCache; // when an entity-server starts up, EntityItem::setActionData is called before the entity-tree is // ready. This means we can't find our EntityItemPointer or add the action to the simulation. These From 7f841b3828d78d144b21dea7b5ef7bf1c33c67dc Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 1 Oct 2015 17:55:47 -0700 Subject: [PATCH 07/56] prevent most other-hand accidental firing --- examples/toys/ping_pong_gun/pingPongGun.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toys/ping_pong_gun/pingPongGun.js index a980fc1bd3..8610c48a96 100644 --- a/examples/toys/ping_pong_gun/pingPongGun.js +++ b/examples/toys/ping_pong_gun/pingPongGun.js @@ -84,6 +84,7 @@ var _t = this; this.canShootTimeout = Script.setTimeout(function() { _t.canShoot = false; + _t.whichHand=null; }, 250) }, @@ -97,7 +98,7 @@ if (this.triggerValue < RELOAD_THRESHOLD) { // print('RELOAD'); this.canShoot = true; - } else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true) { + } else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true && this.hand === this.whichHand) { var gunProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); this.shootBall(gunProperties); this.canShoot = false; From 9f27e5ff1fb260bc313fd8c9c08775ab8eae47f9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 1 Oct 2015 18:21:53 -0700 Subject: [PATCH 08/56] back out a couple other unneeded changes --- libraries/entities/src/EntityItem.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2c18ac5cfd..87967629dd 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1606,7 +1606,6 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { _actionsToRemove.clear(); _allActionsDataCache.clear(); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; - _actionDataDirty = true; }); return true; } @@ -1719,10 +1718,8 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { assertWriteLocked(); checkWaitingToRemove(); - if (_allActionsDataCache != actionData) { - _allActionsDataCache = actionData; - deserializeActionsInternal(); - } + _allActionsDataCache = actionData; + deserializeActionsInternal(); } QByteArray EntityItem::serializeActions(bool& success) const { From 6131875f674637ef052cf1ab6df7a44617892dfc Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 1 Oct 2015 18:49:07 -0700 Subject: [PATCH 09/56] set whichhand to null on release --- examples/toys/ping_pong_gun/pingPongGun.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toys/ping_pong_gun/pingPongGun.js index 8610c48a96..1616d9c7e2 100644 --- a/examples/toys/ping_pong_gun/pingPongGun.js +++ b/examples/toys/ping_pong_gun/pingPongGun.js @@ -82,10 +82,15 @@ releaseGrab: function() { var _t = this; - this.canShootTimeout = Script.setTimeout(function() { - _t.canShoot = false; - _t.whichHand=null; - }, 250) + + if (this.whichHand === this.hand) { + _t.whichHand = null; + this.canShootTimeout = Script.setTimeout(function() { + _t.canShoot = false; + + }, 250) + } + }, checkTriggerPressure: function(gunHand) { From 82828fdd14053fc489fcf7acae5b371adf95080e Mon Sep 17 00:00:00 2001 From: James Pollack Date: Fri, 2 Oct 2015 10:41:49 -0700 Subject: [PATCH 10/56] reduce gravity and gun force so ball goes through less objects --- examples/toys/ping_pong_gun/pingPongGun.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toys/ping_pong_gun/pingPongGun.js index 1616d9c7e2..7afb467eb0 100644 --- a/examples/toys/ping_pong_gun/pingPongGun.js +++ b/examples/toys/ping_pong_gun/pingPongGun.js @@ -23,12 +23,12 @@ var RELOAD_THRESHOLD = 0.95; var GUN_TIP_FWD_OFFSET = 0.45; var GUN_TIP_UP_OFFSET = 0.040; - var GUN_FORCE = 15; + var GUN_FORCE = 8; var BALL_RESTITUTION = 0.6; var BALL_LINEAR_DAMPING = 0.4; var BALL_GRAVITY = { x: 0, - y: -9.8, + y: -5.8, z: 0 }; From c6fa132dc2d88f29a547f7b000f076dd755adba5 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Fri, 2 Oct 2015 10:44:26 -0700 Subject: [PATCH 11/56] cleanup --- examples/toys/ping_pong_gun/pingPongGun.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toys/ping_pong_gun/pingPongGun.js index 7afb467eb0..b3545ce529 100644 --- a/examples/toys/ping_pong_gun/pingPongGun.js +++ b/examples/toys/ping_pong_gun/pingPongGun.js @@ -36,14 +36,14 @@ x: 0.04, y: 0.04, z: 0.04 - } + }; var BALL_COLOR = { red: 255, green: 255, blue: 255 - } + }; PingPongGun.prototype = { hand: null, @@ -87,8 +87,7 @@ _t.whichHand = null; this.canShootTimeout = Script.setTimeout(function() { _t.canShoot = false; - - }, 250) + }, 250); } }, From 5b970e6b1af1a3d06efd73ce868e53d0d65ea96e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 11:43:19 -0700 Subject: [PATCH 12/56] try to fix double-distance-grabbing lockout --- examples/controllers/handControllerGrab.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5705bd4498..9822f90670 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -87,15 +87,18 @@ function getTag() { } function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. var actionIDs = Entities.getActionIDs(entityID); for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { var actionID = actionIDs[actionIndex]; var actionArguments = Entities.getActionArguments(entityID, actionID); var tag = actionArguments["tag"]; if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. continue; } if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. return true; } } @@ -259,6 +262,7 @@ function MyController(hand, triggerAction) { } else { if (entityIsGrabbedByOther(intersection.entityID)) { // don't allow two people to distance grab the same object + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); return; } // the hand is far from the intersected object. go into distance-holding mode From 880d92ee64d6cd369731c9b2449df4ab6ee214fd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 11:46:48 -0700 Subject: [PATCH 13/56] try to fix double-distance-grabbing lockout --- examples/grab.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/grab.js b/examples/grab.js index 03a227931d..1e0adf9f1b 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -45,26 +45,25 @@ var IDENTITY_QUAT = { z: 0, w: 0 }; -var ACTION_LIFETIME = 120; // 2 minutes +var ACTION_LIFETIME = 10; // seconds function getTag() { return "grab-" + MyAvatar.sessionUUID; } function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. var actionIDs = Entities.getActionIDs(entityID); - var actionIndex; - var actionID; - var actionArguments; - var tag; - for (actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - actionID = actionIDs[actionIndex]; - actionArguments = Entities.getActionArguments(entityID, actionID); - tag = actionArguments.tag; - if (tag === getTag()) { + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. continue; } - if (tag.slice(0, 5) === "grab-") { + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. return true; } } @@ -530,4 +529,4 @@ Controller.mousePressEvent.connect(pressEvent); Controller.mouseMoveEvent.connect(moveEvent); Controller.mouseReleaseEvent.connect(releaseEvent); Controller.keyPressEvent.connect(keyPressEvent); -Controller.keyReleaseEvent.connect(keyReleaseEvent); \ No newline at end of file +Controller.keyReleaseEvent.connect(keyReleaseEvent); From de5e95f7dcdae2e11482c9d106d215b72af7c8fd Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 28 Sep 2015 09:59:18 -0700 Subject: [PATCH 14/56] Improved procedural surfaces, textures and more standard uniforms --- .../src/RenderableBoxEntityItem.cpp | 2 +- .../src/RenderableSphereEntityItem.cpp | 2 +- libraries/gpu/src/gpu/Batch.h | 54 ++-- .../procedural/src/procedural/Procedural.cpp | 246 +++++++++++++----- .../procedural/src/procedural/Procedural.h | 35 ++- .../src/procedural/ProceduralShaders.h | 38 ++- .../src/procedural/ProceduralSkybox.cpp | 36 +-- 7 files changed, 305 insertions(+), 108 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 187b25e75a..077f28350b 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -56,7 +56,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { if (_procedural->ready()) { batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well - _procedural->prepare(batch, this->getDimensions()); + _procedural->prepare(batch, getPosition(), getDimensions()); auto color = _procedural->getColor(cubeColor); batch._glColor4f(color.r, color.g, color.b, color.a); DependencyManager::get()->renderCube(batch); diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 3cfc18046a..246cd2fea7 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -62,7 +62,7 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { modelTransform.postScale(SPHERE_ENTITY_SCALE); if (_procedural->ready()) { batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation - _procedural->prepare(batch, getDimensions()); + _procedural->prepare(batch, getPosition(), getDimensions()); auto color = _procedural->getColor(sphereColor); batch._glColor4f(color.r, color.g, color.b, color.a); DependencyManager::get()->renderSphere(batch); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 2a35d04aac..e1b76e2e81 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -156,24 +156,24 @@ public: // Indirect buffer is used by the multiDrawXXXIndirect calls // The indirect buffer contains the command descriptions to execute multiple drawcalls in a single call void setIndirectBuffer(const BufferPointer& buffer, Offset offset = 0, Offset stride = 0); - - // multi command desctription for multiDrawIndexedIndirect - class DrawIndirectCommand { - public: - uint _count{ 0 }; - uint _instanceCount{ 0 }; - uint _firstIndex{ 0 }; - uint _baseInstance{ 0 }; + + // multi command desctription for multiDrawIndexedIndirect + class DrawIndirectCommand { + public: + uint _count{ 0 }; + uint _instanceCount{ 0 }; + uint _firstIndex{ 0 }; + uint _baseInstance{ 0 }; }; - - // multi command desctription for multiDrawIndexedIndirect - class DrawIndexedIndirectCommand { - public: - uint _count{ 0 }; - uint _instanceCount{ 0 }; - uint _firstIndex{ 0 }; - uint _baseVertex{ 0 }; - uint _baseInstance{ 0 }; + + // multi command desctription for multiDrawIndexedIndirect + class DrawIndexedIndirectCommand { + public: + uint _count{ 0 }; + uint _instanceCount{ 0 }; + uint _firstIndex{ 0 }; + uint _baseVertex{ 0 }; + uint _baseInstance{ 0 }; }; // Transform Stage @@ -246,6 +246,26 @@ public: void _glUniform4iv(int location, int count, const int* value); void _glUniformMatrix4fv(int location, int count, unsigned char transpose, const float* value); + void _glUniform(int location, int v0) { + _glUniform1i(location, v0); + } + + void _glUniform(int location, float v0) { + _glUniform1f(location, v0); + } + + void _glUniform(int location, const glm::vec2& v) { + _glUniform2f(location, v.x, v.y); + } + + void _glUniform(int location, const glm::vec3& v) { + _glUniform3f(location, v.x, v.y, v.z); + } + + void _glUniform(int location, const glm::vec4& v) { + _glUniform4f(location, v.x, v.y, v.z, v.w); + } + void _glColor4f(float red, float green, float blue, float alpha); enum Command { diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index aa8946f62b..334aaca741 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -17,20 +17,30 @@ #include #include #include +#include #include "ProceduralShaders.h" -static const char* const UNIFORM_TIME_NAME= "iGlobalTime"; -static const char* const UNIFORM_SCALE_NAME = "iWorldScale"; +// Userdata parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; - static const QString URL_KEY = "shaderUrl"; static const QString VERSION_KEY = "version"; static const QString UNIFORMS_KEY = "uniforms"; +static const QString CHANNELS_KEY = "channels"; + +// Shader replace strings static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK"; static const std::string PROCEDURAL_COMMON_BLOCK = "//PROCEDURAL_COMMON_BLOCK"; static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; +static const std::string STANDARD_UNIFORM_NAMES[Procedural::NUM_STANDARD_UNIFORMS] = { + "iDate", + "iGlobalTime", + "iFrameCount", + "iWorldScale", + "iWorldPosition", + "iChannelResolution" +}; // Example //{ @@ -100,7 +110,21 @@ void Procedural::parse(const QJsonObject& proceduralData) { { auto uniforms = proceduralData[UNIFORMS_KEY]; if (uniforms.isObject()) { - _uniforms = uniforms.toObject();; + _parsedUniforms = uniforms.toObject(); + } + } + + // Grab any textures + { + auto channels = proceduralData[CHANNELS_KEY]; + if (channels.isArray()) { + auto textureCache = DependencyManager::get(); + _parsedChannels = channels.toArray(); + size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size()); + for (size_t i = 0; i < channelCount; ++i) { + QString url = _parsedChannels.at(i).toString(); + _channels[i] = textureCache->getTexture(QUrl(url)); + } } } _enabled = true; @@ -111,20 +135,26 @@ bool Procedural::ready() { return false; } - if (!_shaderPath.isEmpty()) { - return true; + // Do we have a network or local shader + if (_shaderPath.isEmpty() && (!_networkShader || !_networkShader->isLoaded())) { + return false; } - if (_networkShader) { - return _networkShader->isLoaded(); + // Do we have textures, and if so, are they loaded? + for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { + if (_channels[i] && !_channels[i]->isLoaded()) { + return false; + } } - return false; + return true; } -void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) { +void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size) { + _entityDimensions = size; + _entityPosition = position; if (_shaderUrl.isLocalFile()) { - auto lastModified = (quint64) QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); + auto lastModified = (quint64)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { QFile file(_shaderPath); file.open(QIODevice::ReadOnly); @@ -164,69 +194,169 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) { //qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str(); _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource)); _shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader)); - gpu::Shader::makeProgram(*_shader); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2)); + slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3)); + gpu::Shader::makeProgram(*_shader, slotBindings); + _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state)); - _timeSlot = _shader->getUniforms().findLocation(UNIFORM_TIME_NAME); - _scaleSlot = _shader->getUniforms().findLocation(UNIFORM_SCALE_NAME); + for (size_t i = 0; i < NUM_STANDARD_UNIFORMS; ++i) { + const std::string& name = STANDARD_UNIFORM_NAMES[i]; + _standardUniformSlots[i] = _shader->getUniforms().findLocation(name); + } _start = usecTimestampNow(); + _frameCount = 0; } batch.setPipeline(_pipeline); if (_pipelineDirty) { _pipelineDirty = false; - // Set any userdata specified uniforms - foreach(QString key, _uniforms.keys()) { - std::string uniformName = key.toLocal8Bit().data(); - int32_t slot = _shader->getUniforms().findLocation(uniformName); - if (gpu::Shader::INVALID_LOCATION == slot) { - continue; - } - QJsonValue value = _uniforms[key]; - if (value.isDouble()) { - batch._glUniform1f(slot, value.toDouble()); - } else if (value.isArray()) { - auto valueArray = value.toArray(); - switch (valueArray.size()) { - case 0: - break; + setupUniforms(); + } - case 1: - batch._glUniform1f(slot, valueArray[0].toDouble()); - break; - case 2: - batch._glUniform2f(slot, - valueArray[0].toDouble(), - valueArray[1].toDouble()); - break; - case 3: - batch._glUniform3f(slot, - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble()); - break; - case 4: - default: - batch._glUniform4f(slot, - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - valueArray[3].toDouble()); - break; + for (auto lambda : _uniforms) { + lambda(batch); + } + + for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { + if (_channels[i] && _channels[i]->isLoaded()) { + batch.setResourceTexture(i, _channels[i]->getGPUTexture()); + } + } +} + +void Procedural::setupUniforms() { + _uniforms.clear(); + // Set any userdata specified uniforms + foreach(QString key, _parsedUniforms.keys()) { + std::string uniformName = key.toLocal8Bit().data(); + int32_t slot = _shader->getUniforms().findLocation(uniformName); + if (gpu::Shader::INVALID_LOCATION == slot) { + continue; + } + QJsonValue value = _parsedUniforms[key]; + if (value.isDouble()) { + float v = value.toDouble(); + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform1f(slot, v); + }); + } else if (value.isArray()) { + auto valueArray = value.toArray(); + switch (valueArray.size()) { + case 0: + break; + + case 1: { + float v = valueArray[0].toDouble(); + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform1f(slot, v); + }); + break; + } + case 2: { + glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform2f(slot, v.x, v.y); + }); + break; + } + case 3: { + glm::vec3 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + }; + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform3f(slot, v.x, v.y, v.z); + }); + break; + } + + default: + case 4: { + glm::vec4 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble(), + }; + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform4f(slot, v.x, v.y, v.z, v.w); + }); + break; } - valueArray.size(); } } } - // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds - float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; - batch._glUniform1f(_timeSlot, time); - // FIXME move into the 'set once' section, since this doesn't change over time - batch._glUniform3f(_scaleSlot, size.x, size.y, size.z); -} + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[TIME]) { + _uniforms.push_back([=](gpu::Batch& batch) { + // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds + float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; + batch._glUniform(_standardUniformSlots[TIME], time); + }); + } + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[DATE]) { + _uniforms.push_back([=](gpu::Batch& batch) { + QDateTime now = QDateTime::currentDateTimeUtc(); + QDate date = now.date(); + QTime time = now.time(); + vec4 v; + v.x = date.year(); + // Shadertoy month is 0 based + v.y = date.month() - 1; + // But not the day... go figure + v.z = date.day(); + v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second(); + batch._glUniform(_standardUniformSlots[DATE], v); + }); + } + + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[FRAME_COUNT]) { + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform(_standardUniformSlots[FRAME_COUNT], ++_frameCount); + }); + } + + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) { + // FIXME move into the 'set once' section, since this doesn't change over time + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions); + }); + } + + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) { + // FIXME move into the 'set once' section, since this doesn't change over time + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions); + }); + } + + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[POSITION]) { + // FIXME move into the 'set once' section, since this doesn't change over time + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform(_standardUniformSlots[POSITION], _entityPosition); + }); + } + + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[CHANNEL_RESOLUTION]) { + _uniforms.push_back([=](gpu::Batch& batch) { + vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS]; + for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { + if (_channels[i]) { + channelSizes[i] = vec3(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0); + } + } + batch._glUniform3fv(_standardUniformSlots[CHANNEL_RESOLUTION], MAX_PROCEDURAL_TEXTURE_CHANNELS, &channelSizes[0].x); + }); + } +} glm::vec4 Procedural::getColor(const glm::vec4& entityColor) { if (_version == 1) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 5b3f2b4742..1b02fbd435 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -14,11 +14,16 @@ #include #include #include +#include #include #include #include #include +#include + +using UniformLambdas = std::list>; +const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 }; // FIXME better encapsulation // FIXME better mechanism for extending to things rendered using shaders other than simple.slv @@ -29,7 +34,8 @@ struct Procedural { void parse(const QString& userDataJson); void parse(const QJsonObject&); bool ready(); - void prepare(gpu::Batch& batch, const glm::vec3& size); + void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size); + void setupUniforms(); glm::vec4 getColor(const glm::vec4& entityColor); bool _enabled{ false }; @@ -43,17 +49,34 @@ struct Procedural { QUrl _shaderUrl; quint64 _shaderModified{ 0 }; bool _pipelineDirty{ true }; - int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION }; - int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION }; - uint64_t _start{ 0 }; - NetworkShaderPointer _networkShader; - QJsonObject _uniforms; + enum StandardUniforms { + DATE, + TIME, + FRAME_COUNT, + SCALE, + POSITION, + CHANNEL_RESOLUTION, + NUM_STANDARD_UNIFORMS + }; + + int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS]; + + uint64_t _start{ 0 }; + int32_t _frameCount{ 0 }; + NetworkShaderPointer _networkShader; + QJsonObject _parsedUniforms; + QJsonArray _parsedChannels; + + UniformLambdas _uniforms; + NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; gpu::PipelinePointer _pipeline; gpu::ShaderPointer _vertexShader; gpu::ShaderPointer _fragmentShader; gpu::ShaderPointer _shader; gpu::StatePointer _state; + glm::vec3 _entityDimensions; + glm::vec3 _entityPosition; }; #endif diff --git a/libraries/procedural/src/procedural/ProceduralShaders.h b/libraries/procedural/src/procedural/ProceduralShaders.h index 9943a322cc..eddf53cb09 100644 --- a/libraries/procedural/src/procedural/ProceduralShaders.h +++ b/libraries/procedural/src/procedural/ProceduralShaders.h @@ -262,15 +262,39 @@ float snoise(vec2 v) { return 130.0 * dot(m, g); } -// TODO add more uniforms -uniform float iGlobalTime; // shader playback time (in seconds) -uniform vec3 iWorldScale; // the dimensions of the object being rendered - -// TODO add support for textures -// TODO document available inputs other than the uniforms -// TODO provide world scale in addition to the untransformed position +// shader playback time (in seconds) +uniform float iGlobalTime; +// the dimensions of the object being rendered +uniform vec3 iWorldScale; #define PROCEDURAL 1 //PROCEDURAL_VERSION + +#ifdef PROCEDURAL_V1 + +#else + +// Unimplemented uniforms +// Resolution doesn't make sense in the VR context +const vec3 iResolution = vec3(1.0); +// Mouse functions not enabled currently +const vec4 iMouse = vec4(0.0); +// No support for audio input +const float iSampleRate = 1.0; +// No support for video input +const vec4 iChannelTime = vec4(0.0); + + +uniform vec4 iDate; +uniform int iFrameCount; +uniform vec3 iWorldPosition; +uniform vec3 iChannelResolution[4]; +uniform sampler2D iChannel0; +uniform sampler2D iChannel1; +uniform sampler2D iChannel2; +uniform sampler2D iChannel3; + +#endif + )SHADER"; diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 1c7e7e457c..022bf7898a 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -1,20 +1,20 @@ -// -// ProceduralSkybox.cpp -// libraries/procedural/src/procedural -// -// Created by Sam Gateau on 9/21/2015. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "ProceduralSkybox.h" - - -#include -#include -#include - +// +// ProceduralSkybox.cpp +// libraries/procedural/src/procedural +// +// Created by Sam Gateau on 9/21/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "ProceduralSkybox.h" + + +#include +#include +#include + #include "ProceduralSkybox_vert.h" #include "ProceduralSkybox_frag.h" @@ -74,7 +74,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setResourceTexture(0, skybox.getCubemap()); } - skybox._procedural->prepare(batch, glm::vec3(1)); + skybox._procedural->prepare(batch, glm::vec3(0), glm::vec3(1)); batch.draw(gpu::TRIANGLE_STRIP, 4); } } From 7d4b6802559e5043f71e05fffbb8befa24a9c3f4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 30 Sep 2015 09:48:08 -0700 Subject: [PATCH 15/56] PR comments --- .../procedural/src/procedural/Procedural.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 334aaca741..18b6765d89 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -248,24 +248,26 @@ void Procedural::setupUniforms() { } else if (value.isArray()) { auto valueArray = value.toArray(); switch (valueArray.size()) { - case 0: - break; + case 0: + break; - case 1: { + case 1: { float v = valueArray[0].toDouble(); _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); break; } - case 2: { + + case 2: { glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); break; } - case 3: { + + case 3: { glm::vec3 v{ valueArray[0].toDouble(), valueArray[1].toDouble(), @@ -277,8 +279,8 @@ void Procedural::setupUniforms() { break; } - default: - case 4: { + default: + case 4: { glm::vec4 v{ valueArray[0].toDouble(), valueArray[1].toDouble(), From 83c9ebf06cfe00e3a0226484dfd594263a40e318 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 2 Oct 2015 11:38:19 -0700 Subject: [PATCH 16/56] Fixing Linux build failure --- libraries/model-networking/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model-networking/CMakeLists.txt b/libraries/model-networking/CMakeLists.txt index 3613f76cff..f014885794 100644 --- a/libraries/model-networking/CMakeLists.txt +++ b/libraries/model-networking/CMakeLists.txt @@ -7,5 +7,5 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared networking gpu model) +link_hifi_libraries(shared networking gpu model fbx) From c0e8b02a2fddc5768c1b6bc97d225523f47ce44b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 12:25:34 -0700 Subject: [PATCH 17/56] fix what happens when a distance grab is blocked because someone else already has it --- examples/controllers/handControllerGrab.js | 54 ++++++++++++---------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9822f90670..f4a6d1790d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -167,6 +167,12 @@ function MyController(hand, triggerAction) { } }; + this.setState = function(newState) { + // print("STATE: " + this.state + " --> " + newState); + this.state = newState; + } + + this.lineOn = function(closePoint, farPoint, color) { // draw a line if (this.pointer === null) { @@ -220,14 +226,14 @@ function MyController(hand, triggerAction) { this.off = function() { if (this.triggerSmoothedSqueezed()) { - this.state = STATE_SEARCHING; + this.setState(STATE_SEARCHING); return; } } this.search = function() { if (this.triggerSmoothedReleased()) { - this.state = STATE_RELEASE; + this.setState(STATE_RELEASE); return; } @@ -238,6 +244,8 @@ function MyController(hand, triggerAction) { direction: Quat.getUp(this.getHandRotation()) }; + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + var defaultGrabbableData = { grabbable: true }; @@ -253,21 +261,20 @@ function MyController(hand, triggerAction) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, defaultGrabbableData); if (grabbableData.grabbable === false) { + this.grabbedEntity = null; return; } if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) { // the hand is very close to the intersected object. go into close-grabbing mode. - this.state = STATE_NEAR_GRABBING; - + this.setState(STATE_NEAR_GRABBING); } else { + // don't allow two people to distance grab the same object if (entityIsGrabbedByOther(intersection.entityID)) { - // don't allow two people to distance grab the same object - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - return; + this.grabbedEntity = null; + } else { + // the hand is far from the intersected object. go into distance-holding mode + this.setState(STATE_DISTANCE_HOLDING); } - // the hand is far from the intersected object. go into distance-holding mode - this.state = STATE_DISTANCE_HOLDING; - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } } else { // forward ray test failed, try sphere test. @@ -291,15 +298,14 @@ function MyController(hand, triggerAction) { } } if (this.grabbedEntity === null) { - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + // this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } else if (props.locked === 0 && props.collisionsWillMove === 1) { - this.state = STATE_NEAR_GRABBING; + this.setState(STATE_NEAR_GRABBING); } else if (props.collisionsWillMove === 0) { // We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event - this.state = STATE_NEAR_GRABBING_NON_COLLIDING; + this.setState(STATE_NEAR_GRABBING_NON_COLLIDING); } } - }; this.distanceHolding = function() { @@ -329,7 +335,7 @@ function MyController(hand, triggerAction) { } if (this.actionID !== null) { - this.state = STATE_CONTINUE_DISTANCE_HOLDING; + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); this.activateEntity(this.grabbedEntity); if (this.hand === RIGHT_HAND) { Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); @@ -346,7 +352,7 @@ function MyController(hand, triggerAction) { this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { - this.state = STATE_RELEASE; + this.setState(STATE_RELEASE); return; } @@ -404,7 +410,7 @@ function MyController(hand, triggerAction) { var now = Date.now(); var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds this.computeReleaseVelocity(deltaPosition, deltaTime, false); - + this.currentObjectPosition = newObjectPosition; this.currentObjectTime = now; @@ -427,7 +433,7 @@ function MyController(hand, triggerAction) { this.nearGrabbing = function() { if (this.triggerSmoothedReleased()) { - this.state = STATE_RELEASE; + this.setState(STATE_RELEASE); return; } @@ -458,7 +464,7 @@ function MyController(hand, triggerAction) { if (this.actionID === NULL_ACTION_ID) { this.actionID = null; } else { - this.state = STATE_CONTINUE_NEAR_GRABBING; + this.setState(STATE_CONTINUE_NEAR_GRABBING); if (this.hand === RIGHT_HAND) { Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); } else { @@ -475,7 +481,7 @@ function MyController(hand, triggerAction) { this.continueNearGrabbing = function() { if (this.triggerSmoothedReleased()) { - this.state = STATE_RELEASE; + this.setState(STATE_RELEASE); return; } @@ -502,7 +508,7 @@ function MyController(hand, triggerAction) { this.nearGrabbingNonColliding = function() { if (this.triggerSmoothedReleased()) { - this.state = STATE_RELEASE; + this.setState(STATE_RELEASE); return; } if (this.hand === RIGHT_HAND) { @@ -511,12 +517,12 @@ function MyController(hand, triggerAction) { Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); } Entities.callEntityMethod(this.grabbedEntity, "startNearGrabNonColliding"); - this.state = STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING; + this.setState(STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING); }; this.continueNearGrabbingNonColliding = function() { if (this.triggerSmoothedReleased()) { - this.state = STATE_RELEASE; + this.setState(STATE_RELEASE); return; } Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding"); @@ -627,7 +633,7 @@ function MyController(hand, triggerAction) { this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; this.actionID = null; - this.state = STATE_OFF; + this.setState(STATE_OFF); }; this.cleanup = function() { From 0497de47ea41f540d3364955980a089551d46d7e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 2 Oct 2015 12:40:14 -0700 Subject: [PATCH 18/56] No longer removing non-existent entities from spray paint can; color tweaks to paint stream --- examples/toys/sprayPaintCan.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/examples/toys/sprayPaintCan.js b/examples/toys/sprayPaintCan.js index e0aeb19995..251827ead7 100644 --- a/examples/toys/sprayPaintCan.js +++ b/examples/toys/sprayPaintCan.js @@ -9,7 +9,7 @@ // -(function() { +(function () { // Script.include("../libraries/utils.js"); //Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge @@ -33,19 +33,19 @@ var MIN_POINT_DISTANCE = 0.01; var STROKE_WIDTH = 0.02; - this.setRightHand = function() { + this.setRightHand = function () { this.hand = 'RIGHT'; } - this.setLeftHand = function() { + this.setLeftHand = function () { this.hand = 'LEFT'; } - this.startNearGrab = function() { + this.startNearGrab = function () { this.whichHand = this.hand; } - this.toggleWithTriggerPressure = function() { + this.toggleWithTriggerPressure = function () { var handClickString = this.whichHand + "_HAND_CLICK"; var handClick = Controller.findAction(handClickString); @@ -60,7 +60,7 @@ } } - this.enableStream = function() { + this.enableStream = function () { var position = Entities.getEntityProperties(this.entityId, "position").position; var animationSettings = JSON.stringify({ fps: 30, @@ -85,6 +85,11 @@ particleRadius: 0.01, radiusSpread: 0.005, polarFinish: 0.05, + colorStart: { + red: 50, + green: 10, + blue: 150 + }, color: { red: 170, green: 20, @@ -105,11 +110,11 @@ } - this.releaseGrab = function() { + this.releaseGrab = function () { this.disableStream(); } - this.disableStream = function() { + this.disableStream = function () { Entities.deleteEntity(this.paintStream); this.paintStream = null; this.spraying = false; @@ -117,7 +122,7 @@ } - this.continueNearGrab = function() { + this.continueNearGrab = function () { this.toggleWithTriggerPressure(); @@ -143,7 +148,7 @@ }); } - this.preload = function(entityId) { + this.preload = function (entityId) { this.sprayVolume = 0.1; this.spraying = false; this.entityId = entityId; @@ -151,12 +156,9 @@ } - this.unload = function() { + this.unload = function () { if (this.paintStream) { Entities.deleteEntity(this.paintStream); } - this.strokes.forEach(function(stroke) { - Entities.deleteEntity(stroke); - }); } -}); +}); \ No newline at end of file From 67cc944afc27ce9182b716a9b7c4ab07547901e6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 13:27:45 -0700 Subject: [PATCH 19/56] fix double free problem --- libraries/entities/src/EntityItem.cpp | 22 +++++++++++----------- libraries/entities/src/EntityItem.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 87967629dd..a031fbb196 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1528,7 +1528,8 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi simulation->addAction(action); bool success; - QByteArray newDataCache = serializeActions(success); + QByteArray newDataCache; + serializeActions(success, newDataCache); if (success) { _allActionsDataCache = newDataCache; _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; @@ -1549,7 +1550,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI success = action->updateArguments(arguments); if (success) { - _allActionsDataCache = serializeActions(success); + serializeActions(success, _allActionsDataCache); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } else { qDebug() << "EntityItem::updateAction failed"; @@ -1585,7 +1586,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s } bool success = true; - _allActionsDataCache = serializeActions(success); + serializeActions(success, _allActionsDataCache); _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; return success; } @@ -1722,13 +1723,13 @@ void EntityItem::setActionDataInternal(QByteArray actionData) { deserializeActionsInternal(); } -QByteArray EntityItem::serializeActions(bool& success) const { +void EntityItem::serializeActions(bool& success, QByteArray& result) const { assertLocked(); - QByteArray result; if (_objectActions.size() == 0) { success = true; - return QByteArray(); + result.clear(); + return; } QVector serializedActions; @@ -1746,21 +1747,20 @@ QByteArray EntityItem::serializeActions(bool& success) const { if (result.size() >= _maxActionsDataSize) { success = false; - return result; + return; } success = true; - return result; + return; } const QByteArray EntityItem::getActionDataInternal() const { if (_actionDataDirty) { bool success; - QByteArray newDataCache = serializeActions(success); + serializeActions(success, _allActionsDataCache); if (success) { - _allActionsDataCache = newDataCache; + _actionDataDirty = false; } - _actionDataDirty = false; } return _allActionsDataCache; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c856794322..7b1537bbc3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -508,7 +508,7 @@ protected: bool addActionInternal(EntitySimulation* simulation, EntityActionPointer action); bool removeActionInternal(const QUuid& actionID, EntitySimulation* simulation = nullptr); void deserializeActionsInternal(); - QByteArray serializeActions(bool& success) const; + void serializeActions(bool& success, QByteArray& result) const; QHash _objectActions; static int _maxActionsDataSize; From cf8955a8c5801dbf38f62926861030752b745dce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 15:27:01 -0700 Subject: [PATCH 20/56] kinematic grab --- interface/src/InterfaceActionFactory.cpp | 3 + .../src/avatar/AvatarActionKinematicHold.cpp | 162 ++++++++++++++++++ .../src/avatar/AvatarActionKinematicHold.h | 41 +++++ .../entities/src/EntityActionInterface.cpp | 5 + .../entities/src/EntityActionInterface.h | 3 +- 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 interface/src/avatar/AvatarActionKinematicHold.cpp create mode 100644 interface/src/avatar/AvatarActionKinematicHold.h diff --git a/interface/src/InterfaceActionFactory.cpp b/interface/src/InterfaceActionFactory.cpp index 2879c19eaa..b4bd7c45ae 100644 --- a/interface/src/InterfaceActionFactory.cpp +++ b/interface/src/InterfaceActionFactory.cpp @@ -12,6 +12,7 @@ #include +#include #include #include @@ -28,6 +29,8 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); case ACTION_TYPE_HOLD: return (EntityActionPointer) new AvatarActionHold(id, ownerEntity); + case ACTION_TYPE_KINEMATIC_HOLD: + return (EntityActionPointer) new AvatarActionKinematicHold(id, ownerEntity); } assert(false); diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp new file mode 100644 index 0000000000..14b80efd64 --- /dev/null +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -0,0 +1,162 @@ +// +// AvatarActionKinematicHold.cpp +// interface/src/avatar/ +// +// Created by Seth Alves 2015-6-9 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QVariantGLM.h" +#include "avatar/MyAvatar.h" +#include "avatar/AvatarManager.h" + +#include "AvatarActionKinematicHold.h" + +const uint16_t AvatarActionKinematicHold::holdVersion = 1; + +AvatarActionKinematicHold::AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity) : + ObjectActionSpring(id, ownerEntity), + _relativePosition(glm::vec3(0.0f)), + _relativeRotation(glm::quat()), + _hand("right"), + _mine(false) +{ + _type = ACTION_TYPE_HOLD; + #if WANT_DEBUG + qDebug() << "AvatarActionKinematicHold::AvatarActionKinematicHold"; + #endif +} + +AvatarActionKinematicHold::~AvatarActionKinematicHold() { + #if WANT_DEBUG + qDebug() << "AvatarActionKinematicHold::~AvatarActionKinematicHold"; + #endif +} + +void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { + if (!_mine) { + // if a local script isn't updating this, then we are just getting spring-action data over the wire. + // let the super-class handle it. + ObjectActionSpring::updateActionWorker(deltaTimeStep); + return; + } + + glm::quat rotation; + glm::vec3 position; + glm::vec3 offset; + bool gotLock = withTryReadLock([&]{ + auto myAvatar = DependencyManager::get()->getMyAvatar(); + glm::vec3 palmPosition; + glm::quat palmRotation; + if (_hand == "right") { + palmPosition = myAvatar->getRightPalmPosition(); + palmRotation = myAvatar->getRightPalmRotation(); + } else { + palmPosition = myAvatar->getLeftPalmPosition(); + palmRotation = myAvatar->getLeftPalmRotation(); + } + + rotation = palmRotation * _relativeRotation; + offset = rotation * _relativePosition; + position = palmPosition + offset; + }); + + if (gotLock) { + gotLock = withTryWriteLock([&]{ + if (_positionalTarget != position || _rotationalTarget != rotation) { + _positionalTarget = position; + _rotationalTarget = rotation; + auto ownerEntity = _ownerEntity.lock(); + if (ownerEntity) { + ownerEntity->setActionDataDirty(true); + void* physicsInfo = ownerEntity->getPhysicsInfo(); + if (physicsInfo) { + ObjectMotionState* motionState = static_cast(physicsInfo); + btRigidBody* rigidBody = motionState->getRigidBody(); + if (!rigidBody) { + qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody"; + return; + } + + btTransform worldTrans; + worldTrans.setOrigin(glmToBullet(_positionalTarget)); + worldTrans.setRotation(glmToBullet(_rotationalTarget)); + rigidBody->setWorldTransform(worldTrans); + } + } + } + }); + } + + if (gotLock) { + ObjectActionSpring::updateActionWorker(deltaTimeStep); + } +} + + +bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) { + if (!ObjectAction::updateArguments(arguments)) { + return false; + } + bool ok = true; + glm::vec3 relativePosition = + EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); + if (!ok) { + relativePosition = _relativePosition; + } + + ok = true; + glm::quat relativeRotation = + EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); + if (!ok) { + relativeRotation = _relativeRotation; + } + + ok = true; + QString hand = + EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false); + if (!ok || !(hand == "left" || hand == "right")) { + hand = _hand; + } + + if (relativePosition != _relativePosition + || relativeRotation != _relativeRotation + || hand != _hand) { + withWriteLock([&] { + _relativePosition = relativePosition; + _relativeRotation = relativeRotation; + _hand = hand; + + _mine = true; + _active = true; + activateBody(); + }); + } + return true; +} + + +QVariantMap AvatarActionKinematicHold::getArguments() { + QVariantMap arguments = ObjectAction::getArguments(); + withReadLock([&]{ + if (!_mine) { + arguments = ObjectActionSpring::getArguments(); + return; + } + + arguments["relativePosition"] = glmToQMap(_relativePosition); + arguments["relativeRotation"] = glmToQMap(_relativeRotation); + arguments["hand"] = _hand; + }); + return arguments; +} + + +void AvatarActionKinematicHold::deserialize(QByteArray serializedArguments) { + if (!_mine) { + ObjectActionSpring::deserialize(serializedArguments); + } +} diff --git a/interface/src/avatar/AvatarActionKinematicHold.h b/interface/src/avatar/AvatarActionKinematicHold.h new file mode 100644 index 0000000000..6bd7dca01a --- /dev/null +++ b/interface/src/avatar/AvatarActionKinematicHold.h @@ -0,0 +1,41 @@ +// +// AvatarActionKinematicHold.h +// interface/src/avatar/ +// +// Created by Seth Alves 2015-10-2 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AvatarActionKinematicHold_h +#define hifi_AvatarActionKinematicHold_h + +#include + +#include +#include + +class AvatarActionKinematicHold : public ObjectActionSpring { +public: + AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity); + virtual ~AvatarActionKinematicHold(); + + virtual bool updateArguments(QVariantMap arguments); + virtual QVariantMap getArguments(); + + virtual void updateActionWorker(float deltaTimeStep); + + virtual void deserialize(QByteArray serializedArguments); + +private: + static const uint16_t holdVersion; + + glm::vec3 _relativePosition; + glm::quat _relativeRotation; + QString _hand; + bool _mine = false; +}; + +#endif // hifi_AvatarActionKinematicHold_h diff --git a/libraries/entities/src/EntityActionInterface.cpp b/libraries/entities/src/EntityActionInterface.cpp index ba7f3afea4..d821dcdc2f 100644 --- a/libraries/entities/src/EntityActionInterface.cpp +++ b/libraries/entities/src/EntityActionInterface.cpp @@ -100,6 +100,9 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS if (normalizedActionTypeString == "hold") { return ACTION_TYPE_HOLD; } + if (normalizedActionTypeString == "kinematic-hold") { + return ACTION_TYPE_KINEMATIC_HOLD; + } qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString; return ACTION_TYPE_NONE; @@ -115,6 +118,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) { return "spring"; case ACTION_TYPE_HOLD: return "hold"; + case ACTION_TYPE_KINEMATIC_HOLD: + return "kinematic-hold"; } assert(false); return "none"; diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index e61019c98c..567b88d4b0 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -23,7 +23,8 @@ enum EntityActionType { ACTION_TYPE_NONE = 0, ACTION_TYPE_OFFSET = 1000, ACTION_TYPE_SPRING = 2000, - ACTION_TYPE_HOLD = 3000 + ACTION_TYPE_HOLD = 3000, + ACTION_TYPE_KINEMATIC_HOLD = 4000 }; From 9427ba1a5ac38d9569ddfe2f4c482fe33c566544 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Fri, 2 Oct 2015 15:56:26 -0700 Subject: [PATCH 21/56] ping pong gun --- examples/toys/ping_pong_gun/createPingPongGun.js | 12 ++++++------ examples/toys/ping_pong_gun/pingPongGun.js | 11 +++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/examples/toys/ping_pong_gun/createPingPongGun.js b/examples/toys/ping_pong_gun/createPingPongGun.js index 4b7ed27643..4969a0bc72 100644 --- a/examples/toys/ping_pong_gun/createPingPongGun.js +++ b/examples/toys/ping_pong_gun/createPingPongGun.js @@ -13,8 +13,8 @@ Script.include("../../utilities.js"); var scriptURL = Script.resolvePath('pingPongGun.js'); -var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx' -var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj'; +var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx?123' +var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj?123'; var center = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, @@ -30,9 +30,9 @@ var pingPongGun = Entities.addEntity({ script: scriptURL, position: center, dimensions: { - x:0.67, - y: 0.14, - z: 0.09 + x: 0.08, + y: 0.21, + z: 0.47 }, collisionsWillMove: true, }); @@ -40,4 +40,4 @@ var pingPongGun = Entities.addEntity({ function cleanUp() { Entities.deleteEntity(pingPongGun); } -Script.scriptEnding.connect(cleanUp); +Script.scriptEnding.connect(cleanUp); \ No newline at end of file diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toys/ping_pong_gun/pingPongGun.js index b3545ce529..298d93a523 100644 --- a/examples/toys/ping_pong_gun/pingPongGun.js +++ b/examples/toys/ping_pong_gun/pingPongGun.js @@ -81,15 +81,14 @@ }, releaseGrab: function() { - var _t = this; + var _this = this; if (this.whichHand === this.hand) { - _t.whichHand = null; + this.whichHand = null; this.canShootTimeout = Script.setTimeout(function() { - _t.canShoot = false; + _this.canShoot = false; }, 250); } - }, checkTriggerPressure: function(gunHand) { @@ -107,6 +106,7 @@ this.shootBall(gunProperties); this.canShoot = false; } + return; }, @@ -114,6 +114,7 @@ var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, -90, 0))); forwardVec = Vec3.normalize(forwardVec); forwardVec = Vec3.multiply(forwardVec, GUN_FORCE); + var properties = { type: 'Sphere', color: BALL_COLOR, @@ -148,8 +149,10 @@ var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET); var upVector = Quat.getRight(properties.rotation); var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET); + var gunTipPosition = Vec3.sum(properties.position, frontOffset); gunTipPosition = Vec3.sum(gunTipPosition, upOffset); + return gunTipPosition; }, From 01044e3c056178c28b7ed1f9e8d5d351f18e7764 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Fri, 2 Oct 2015 15:57:46 -0700 Subject: [PATCH 22/56] adjust gun dimensions in toybox master script --- unpublishedScripts/masterReset.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index d6759e2b48..13445ca438 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -98,7 +98,7 @@ function createAllToys() { function deleteAllToys() { var entities = Entities.findEntities(MyAvatar.position, 100); - entities.forEach(function (entity) { + entities.forEach(function(entity) { //params: customKey, id, defaultValue var shouldReset = getEntityCustomData(resetKey, entity, {}).resetMe; if (shouldReset === true) { @@ -468,9 +468,9 @@ function createPingPongBallGun() { z: 0 }, dimensions: { - x: 0.67, - y: 0.14, - z: 0.09 + x: 0.08, + y: 0.21, + z: 0.47 }, collisionsWillMove: true, }); @@ -831,4 +831,4 @@ function cleanup() { if (shouldDeleteOnEndScript) { Script.scriptEnding.connect(cleanup); -} +} \ No newline at end of file From b6b57de1c6b870cbd026ad21fa22e01bf622643e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 2 Oct 2015 16:42:50 -0700 Subject: [PATCH 23/56] animation lib warning fixes --- libraries/animation/src/AnimClip.cpp | 2 +- libraries/animation/src/AnimInverseKinematics.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index c432b3b9ac..0d181f8e47 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -159,7 +159,7 @@ void AnimClip::copyFromNetworkAnim() { // used to adjust translation offsets, so large translation animatons on the reference skeleton // will be adjusted when played on a skeleton with short limbs. - float limbLengthScale = fabs(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans)); + float limbLengthScale = (float)fabs(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans)); AnimPose& pose = _anim[frame][skeletonJoint]; const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame]; diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index 2eb0d9b08e..171bcc11d8 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -52,7 +52,7 @@ protected: void computeTargets(const AnimVariantMap& animVars, std::vector& targets, const AnimPoseVec& underPoses); void solveWithCyclicCoordinateDescent(const std::vector& targets); - virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton); + virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override; // for AnimDebugDraw rendering virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; } From 89c848d8c8c4351d656361f8a6c0fbdd2ba02be9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 17:14:53 -0700 Subject: [PATCH 24/56] fix up kinematic hold --- examples/controllers/handControllerGrab.js | 2 +- .../src/avatar/AvatarActionKinematicHold.cpp | 24 +++++++++++++++++-- .../src/avatar/AvatarActionKinematicHold.h | 4 ++++ .../entities/src/EntityActionInterface.cpp | 2 +- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5705bd4498..a8a95cb4ca 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -444,7 +444,7 @@ function MyController(hand, triggerAction) { var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { + this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, { hand: this.hand === RIGHT_HAND ? "right" : "left", timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: offsetPosition, diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index 14b80efd64..e890d8cbd8 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -22,7 +22,9 @@ AvatarActionKinematicHold::AvatarActionKinematicHold(const QUuid& id, EntityItem _relativePosition(glm::vec3(0.0f)), _relativeRotation(glm::quat()), _hand("right"), - _mine(false) + _mine(false), + _previousPositionalTarget(Vectors::ZERO), + _previousRotationalTarget(Quaternions::IDENTITY) { _type = ACTION_TYPE_HOLD; #if WANT_DEBUG @@ -44,6 +46,10 @@ void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { return; } + if (deltaTimeStep <= 0.0f) { + return; + } + glm::quat rotation; glm::vec3 position; glm::vec3 offset; @@ -81,10 +87,24 @@ void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { return; } - btTransform worldTrans; + btTransform worldTrans = rigidBody->getWorldTransform(); worldTrans.setOrigin(glmToBullet(_positionalTarget)); worldTrans.setRotation(glmToBullet(_rotationalTarget)); rigidBody->setWorldTransform(worldTrans); + + if (_previousSet) { + glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep; + rigidBody->setLinearVelocity(glmToBullet(positionalVelocity)); + + glm::quat rotationalDelta = glm::inverse(_previousRotationalTarget) * _rotationalTarget; + glm::vec3 rotationalDeltaAxis = glm::axis(rotationalDelta); + float rotationalDeltaAngle = glm::angle(rotationalDelta); + glm::vec3 rotationalVelocity = glm::normalize(rotationalDeltaAxis) * rotationalDeltaAngle / deltaTimeStep; + rigidBody->setAngularVelocity(glmToBullet(rotationalVelocity)); + } + _previousPositionalTarget = _positionalTarget; + _previousRotationalTarget = _rotationalTarget; + _previousSet = true; } } } diff --git a/interface/src/avatar/AvatarActionKinematicHold.h b/interface/src/avatar/AvatarActionKinematicHold.h index 6bd7dca01a..95e9605c2b 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.h +++ b/interface/src/avatar/AvatarActionKinematicHold.h @@ -36,6 +36,10 @@ private: glm::quat _relativeRotation; QString _hand; bool _mine = false; + + bool _previousSet = false; + glm::vec3 _previousPositionalTarget; + glm::quat _previousRotationalTarget; }; #endif // hifi_AvatarActionKinematicHold_h diff --git a/libraries/entities/src/EntityActionInterface.cpp b/libraries/entities/src/EntityActionInterface.cpp index d821dcdc2f..25f61fcf25 100644 --- a/libraries/entities/src/EntityActionInterface.cpp +++ b/libraries/entities/src/EntityActionInterface.cpp @@ -100,7 +100,7 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS if (normalizedActionTypeString == "hold") { return ACTION_TYPE_HOLD; } - if (normalizedActionTypeString == "kinematic-hold") { + if (normalizedActionTypeString == "kinematichold") { return ACTION_TYPE_KINEMATIC_HOLD; } From 6a770a870b98be3d9120d50fcfcd3ad0fd7fc026 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 17:31:45 -0700 Subject: [PATCH 25/56] set correct type in kinematic hold --- interface/src/avatar/AvatarActionKinematicHold.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index e890d8cbd8..21f2989299 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -26,7 +26,7 @@ AvatarActionKinematicHold::AvatarActionKinematicHold(const QUuid& id, EntityItem _previousPositionalTarget(Vectors::ZERO), _previousRotationalTarget(Quaternions::IDENTITY) { - _type = ACTION_TYPE_HOLD; + _type = ACTION_TYPE_KINEMATIC_HOLD; #if WANT_DEBUG qDebug() << "AvatarActionKinematicHold::AvatarActionKinematicHold"; #endif @@ -95,12 +95,6 @@ void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { if (_previousSet) { glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep; rigidBody->setLinearVelocity(glmToBullet(positionalVelocity)); - - glm::quat rotationalDelta = glm::inverse(_previousRotationalTarget) * _rotationalTarget; - glm::vec3 rotationalDeltaAxis = glm::axis(rotationalDelta); - float rotationalDeltaAngle = glm::angle(rotationalDelta); - glm::vec3 rotationalVelocity = glm::normalize(rotationalDeltaAxis) * rotationalDeltaAngle / deltaTimeStep; - rigidBody->setAngularVelocity(glmToBullet(rotationalVelocity)); } _previousPositionalTarget = _positionalTarget; _previousRotationalTarget = _rotationalTarget; @@ -123,21 +117,21 @@ bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) { } bool ok = true; glm::vec3 relativePosition = - EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); + EntityActionInterface::extractVec3Argument("kinematic-hold", arguments, "relativePosition", ok, false); if (!ok) { relativePosition = _relativePosition; } ok = true; glm::quat relativeRotation = - EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); + EntityActionInterface::extractQuatArgument("kinematic-hold", arguments, "relativeRotation", ok, false); if (!ok) { relativeRotation = _relativeRotation; } ok = true; QString hand = - EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false); + EntityActionInterface::extractStringArgument("kinematic-hold", arguments, "hand", ok, false); if (!ok || !(hand == "left" || hand == "right")) { hand = _hand; } From 67a497cda33ed3e31197215c98d0fa3d002d4160 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Oct 2015 17:37:59 -0700 Subject: [PATCH 26/56] Sanitize particle properties and their use Excluding animationSetings because it's unused and will be removed. --- .../entities/src/ParticleEffectEntityItem.cpp | 113 +++++++++++++++--- .../entities/src/ParticleEffectEntityItem.h | 58 ++++++--- 2 files changed, 140 insertions(+), 31 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 40d3853c39..3a823ae2e8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -52,24 +52,48 @@ const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f; const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA; const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA; +const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f; const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000; +const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1; +const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000; const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f; +const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f; +const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f; const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f; +const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 343.2f; // Speed of sound const float ParticleEffectEntityItem::DEFAULT_SPEED_SPREAD = 1.0f; const glm::quat ParticleEffectEntityItem::DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, X_AXIS); // Vertical const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIMENSIONS = glm::vec3(0.0f, 0.0f, 0.0f); // Emit from point +const float ParticleEffectEntityItem::MINIMUM_EMIT_DIMENSION = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_EMIT_DIMENSION = (float)TREE_SCALE; const float ParticleEffectEntityItem::DEFAULT_EMIT_RADIUS_START = 1.0f; // Emit from surface (when emitDimensions > 0) +const float ParticleEffectEntityItem::MINIMUM_EMIT_RADIUS_START = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_EMIT_RADIUS_START = 1.0f; +const float ParticleEffectEntityItem::MINIMUM_POLAR = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_POLAR = PI; const float ParticleEffectEntityItem::DEFAULT_POLAR_START = 0.0f; // Emit along z-axis const float ParticleEffectEntityItem::DEFAULT_POLAR_FINISH = 0.0f; // "" +const float ParticleEffectEntityItem::MINIMUM_AZIMUTH = -PI; +const float ParticleEffectEntityItem::MAXIMUM_AZIMUTH = PI; const float ParticleEffectEntityItem::DEFAULT_AZIMUTH_START = -PI; // Emit full circumference (when polarFinish > 0) const float ParticleEffectEntityItem::DEFAULT_AZIMUTH_FINISH = PI; // "" const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f); +const float ParticleEffectEntityItem::MINIMUM_EMIT_ACCELERATION = -100.0f; // ~ 10g +const float ParticleEffectEntityItem::MAXIMUM_EMIT_ACCELERATION = 100.0f; const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f); +const float ParticleEffectEntityItem::MINIMUM_ACCELERATION_SPREAD = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_ACCELERATION_SPREAD = 100.0f; const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f; +const float ParticleEffectEntityItem::MINIMUM_PARTICLE_RADIUS = 0.0f; +const float ParticleEffectEntityItem::MAXIMUM_PARTICLE_RADIUS = (float)TREE_SCALE; const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; @@ -114,37 +138,82 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() { } +void ParticleEffectEntityItem::setAlphaStart(float alphaStart) { + _alphaStart = glm::clamp(alphaStart, MINIMUM_ALPHA, MAXIMUM_ALPHA); + _isAlphaStartInitialized = true; +} + +void ParticleEffectEntityItem::setAlphaFinish(float alphaFinish) { + _alphaFinish = glm::clamp(alphaFinish, MINIMUM_ALPHA, MAXIMUM_ALPHA); + _isAlphaFinishInitialized = true; +} + void ParticleEffectEntityItem::setEmitSpeed(float emitSpeed) { - _emitSpeed = emitSpeed; + _emitSpeed = glm::clamp(emitSpeed, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED); computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setSpeedSpread(float speedSpread) { - _speedSpread = speedSpread; + _speedSpread = glm::clamp(speedSpread, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED); computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setEmitOrientation(const glm::quat& emitOrientation) { - _emitOrientation = emitOrientation; + _emitOrientation = glm::normalize(emitOrientation); computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setEmitDimensions(const glm::vec3& emitDimensions) { - _emitDimensions = emitDimensions; + _emitDimensions = glm::vec3( + glm::clamp(emitDimensions.x, MINIMUM_EMIT_DIMENSION, MAXIMUM_EMIT_DIMENSION), + glm::clamp(emitDimensions.y, MINIMUM_EMIT_DIMENSION, MAXIMUM_EMIT_DIMENSION), + glm::clamp(emitDimensions.z, MINIMUM_EMIT_DIMENSION, MAXIMUM_EMIT_DIMENSION) + ); computeAndUpdateDimensions(); } +void ParticleEffectEntityItem::setEmitRadiusStart(float emitRadiusStart) { + _emitRadiusStart = glm::clamp(emitRadiusStart, MINIMUM_EMIT_RADIUS_START, MAXIMUM_EMIT_RADIUS_START); +} + void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) { - _emitAcceleration = emitAcceleration; + _emitAcceleration = glm::vec3( + glm::clamp(emitAcceleration.x, MINIMUM_EMIT_ACCELERATION, MAXIMUM_EMIT_ACCELERATION), + glm::clamp(emitAcceleration.x, MINIMUM_EMIT_ACCELERATION, MAXIMUM_EMIT_ACCELERATION), + glm::clamp(emitAcceleration.y, MINIMUM_EMIT_ACCELERATION, MAXIMUM_EMIT_ACCELERATION) + ); computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerationSpread){ - _accelerationSpread = accelerationSpread; + _accelerationSpread = glm::vec3( + glm::clamp(accelerationSpread.x, MINIMUM_ACCELERATION_SPREAD, MAXIMUM_ACCELERATION_SPREAD), + glm::clamp(accelerationSpread.x, MINIMUM_ACCELERATION_SPREAD, MAXIMUM_ACCELERATION_SPREAD), + glm::clamp(accelerationSpread.y, MINIMUM_ACCELERATION_SPREAD, MAXIMUM_ACCELERATION_SPREAD) + ); computeAndUpdateDimensions(); } +void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { + _particleRadius = glm::clamp(particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); +} + +void ParticleEffectEntityItem::setRadiusStart(float radiusStart) { + _radiusStart = glm::clamp(radiusStart, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + _isRadiusStartInitialized = true; +} + +void ParticleEffectEntityItem::setRadiusFinish(float radiusFinish) { + _radiusFinish = glm::clamp(radiusFinish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + _isRadiusFinishInitialized = true; +} + +void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) { + _radiusSpread = glm::clamp(radiusSpread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); +} + + void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error @@ -639,12 +708,12 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleLifetimes[i] -= deltaTime; // if particle has died. - if (_particleLifetimes[i] <= 0.0f) { + if (_particleLifetimes[i] <= 0.0f || _lifespan == 0.0f) { // move head forward _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; } else { - float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0 + float age = 1.0f - _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0 updateRadius(i, age); updateColor(i, age); updateAlpha(i, age); @@ -654,7 +723,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } // emit new particles, but only if animation is playing - if (getAnimationIsPlaying()) { + if (getAnimationIsPlaying() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) { float timeLeftInFrame = deltaTime; while (_timeUntilNextEmit < timeLeftInFrame) { @@ -672,10 +741,18 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _radiusMiddles[i] =_particleRadius; _radiusFinishes[i] = getRadiusFinish(); } else { - float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1.0f) * _radiusSpread / _particleRadius; - _radiusStarts[i] = spreadMultiplier * getRadiusStart(); - _radiusMiddles[i] = spreadMultiplier * _particleRadius; - _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); + float spreadMultiplier; + if (_particleRadius > 0.0f) { + spreadMultiplier = 1.0f + (2.0f * randFloat() - 1.0f) * _radiusSpread / _particleRadius; + } else { + spreadMultiplier = 0.0f; + } + _radiusStarts[i] = + glm::clamp(spreadMultiplier * getRadiusStart(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + _radiusMiddles[i] = + glm::clamp(spreadMultiplier * _particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + _radiusFinishes[i] = + glm::clamp(spreadMultiplier * getRadiusFinish(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); } updateRadius(i, 0.0f); @@ -753,9 +830,12 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { xColor finishColor = getColorFinish(); float spread = 2.0f * randFloat() - 1.0f; - float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red; - float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green; - float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue; + float spreadMultiplierRed = + middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; + float spreadMultiplierGreen = + middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green :1.0f; + float spreadMultiplierBlue = + middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; _colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); _colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); @@ -799,6 +879,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { + maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES); if (_maxParticles != maxParticles) { _maxParticles = maxParticles; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 74d39aa4af..d54cfb2250 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -12,6 +12,7 @@ #define hifi_ParticleEffectEntityItem_h #include + #include "EntityItem.h" class ParticleEffectEntityItem : public EntityItem { @@ -68,22 +69,25 @@ public: void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; } xColor getColorSpread() const { return _colorSpread; } + static const float MAXIMUM_ALPHA; + static const float MINIMUM_ALPHA; + static const float DEFAULT_ALPHA; - void setAlpha(float alpha) { _alpha = alpha; } + void setAlpha(float alpha) { _alpha = glm::clamp(alpha, MINIMUM_ALPHA, MAXIMUM_ALPHA); } float getAlpha() const { return _alpha; } static const float DEFAULT_ALPHA_START; bool _isAlphaStartInitialized = false; - void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; } + void setAlphaStart(float alphaStart); float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; } static const float DEFAULT_ALPHA_FINISH; bool _isAlphaFinishInitialized = false; - void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; } + void setAlphaFinish(float alphaFinish); float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; } static const float DEFAULT_ALPHA_SPREAD; - void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; } + void setAlphaSpread(float alphaSpread) { _alphaSpread = glm::clamp(alphaSpread, MINIMUM_ALPHA, MAXIMUM_ALPHA); } float getAlphaSpread() const { return _alphaSpread; } void updateShapeType(ShapeType type); @@ -117,18 +121,26 @@ public: float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } static const quint32 DEFAULT_MAX_PARTICLES; + static const quint32 MINIMUM_MAX_PARTICLES; + static const quint32 MAXIMUM_MAX_PARTICLES; void setMaxParticles(quint32 maxParticles); quint32 getMaxParticles() const { return _maxParticles; } static const float DEFAULT_LIFESPAN; - void setLifespan(float lifespan) { _lifespan = lifespan; } + static const float MINIMUM_LIFESPAN; + static const float MAXIMUM_LIFESPAN; + void setLifespan(float lifespan) { _lifespan = glm::clamp(lifespan, MINIMUM_LIFESPAN, MAXIMUM_LIFESPAN); } float getLifespan() const { return _lifespan; } static const float DEFAULT_EMIT_RATE; - void setEmitRate(float emitRate) { _emitRate = emitRate; } + static const float MINIMUM_EMIT_RATE; + static const float MAXIMUM_EMIT_RATE; + void setEmitRate(float emitRate) { _emitRate = glm::clamp(emitRate, MINIMUM_EMIT_RATE, MAXIMUM_EMIT_RATE); } float getEmitRate() const { return _emitRate; } static const float DEFAULT_EMIT_SPEED; + static const float MINIMUM_EMIT_SPEED; + static const float MAXIMUM_EMIT_SPEED; void setEmitSpeed(float emitSpeed); float getEmitSpeed() const { return _emitSpeed; } @@ -141,53 +153,69 @@ public: const glm::quat& getEmitOrientation() const { return _emitOrientation; } static const glm::vec3 DEFAULT_EMIT_DIMENSIONS; + static const float MINIMUM_EMIT_DIMENSION; + static const float MAXIMUM_EMIT_DIMENSION; void setEmitDimensions(const glm::vec3& emitDimensions); const glm::vec3& getEmitDimensions() const { return _emitDimensions; } static const float DEFAULT_EMIT_RADIUS_START; - void setEmitRadiusStart(float emitRadiusStart) { _emitRadiusStart = emitRadiusStart; } + static const float MINIMUM_EMIT_RADIUS_START; + static const float MAXIMUM_EMIT_RADIUS_START; + void setEmitRadiusStart(float emitRadiusStart); float getEmitRadiusStart() const { return _emitRadiusStart; } + static const float MINIMUM_POLAR; + static const float MAXIMUM_POLAR; + static const float DEFAULT_POLAR_START; - void setPolarStart(float polarStart) { _polarStart = polarStart; } + void setPolarStart(float polarStart) { _polarStart = glm::clamp(polarStart, MINIMUM_POLAR, MAXIMUM_POLAR); } float getPolarStart() const { return _polarStart; } static const float DEFAULT_POLAR_FINISH; - void setPolarFinish(float polarFinish) { _polarFinish = polarFinish; } + void setPolarFinish(float polarFinish) { _polarFinish = glm::clamp(polarFinish, MINIMUM_POLAR, MAXIMUM_POLAR); } float getPolarFinish() const { return _polarFinish; } + static const float MINIMUM_AZIMUTH; + static const float MAXIMUM_AZIMUTH; + static const float DEFAULT_AZIMUTH_START; - void setAzimuthStart(float azimuthStart) { _azimuthStart = azimuthStart; } + void setAzimuthStart(float azimuthStart) { _azimuthStart = glm::clamp(azimuthStart, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH); } float getAzimuthStart() const { return _azimuthStart; } static const float DEFAULT_AZIMUTH_FINISH; - void setAzimuthFinish(float azimuthFinish) { _azimuthFinish = azimuthFinish; } + void setAzimuthFinish(float azimuthFinish) { _azimuthFinish = glm::clamp(azimuthFinish, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH); } float getAzimuthFinish() const { return _azimuthFinish; } static const glm::vec3 DEFAULT_EMIT_ACCELERATION; + static const float MINIMUM_EMIT_ACCELERATION; + static const float MAXIMUM_EMIT_ACCELERATION; void setEmitAcceleration(const glm::vec3& emitAcceleration); const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; } static const glm::vec3 DEFAULT_ACCELERATION_SPREAD; + static const float MINIMUM_ACCELERATION_SPREAD; + static const float MAXIMUM_ACCELERATION_SPREAD; void setAccelerationSpread(const glm::vec3& accelerationSpread); const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; } static const float DEFAULT_PARTICLE_RADIUS; - void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } + static const float MINIMUM_PARTICLE_RADIUS; + static const float MAXIMUM_PARTICLE_RADIUS; + void setParticleRadius(float particleRadius); float getParticleRadius() const { return _particleRadius; } static const float DEFAULT_RADIUS_START; bool _isRadiusStartInitialized; - void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; } + void setRadiusStart(float radiusStart); float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; } static const float DEFAULT_RADIUS_FINISH; bool _isRadiusFinishInitialized; - void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; } + void setRadiusFinish(float radiusFinish); float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; } static const float DEFAULT_RADIUS_SPREAD; - void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; } + void setRadiusSpread(float radiusSpread); float getRadiusSpread() const { return _radiusSpread; } void computeAndUpdateDimensions(); From 26310d8ce421369193be808b451cf09d7418c787 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 2 Oct 2015 17:54:09 -0700 Subject: [PATCH 27/56] kill gravity in near-held objects --- examples/controllers/handControllerGrab.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index a8a95cb4ca..d143df1e83 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -431,7 +431,7 @@ function MyController(hand, triggerAction) { this.activateEntity(this.grabbedEntity); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", "gravity"]); var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); @@ -443,6 +443,9 @@ function MyController(hand, triggerAction) { var offset = Vec3.subtract(currentObjectPosition, handPosition); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); + this.saveGravity = grabbedProperties.gravity; + Entities.editEntity(this.grabbedEntity, {gravity: {x:0, y:0, z:0}}); + this.actionID = NULL_ACTION_ID; this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, { hand: this.hand === RIGHT_HAND ? "right" : "left", @@ -472,6 +475,7 @@ function MyController(hand, triggerAction) { this.continueNearGrabbing = function() { if (this.triggerSmoothedReleased()) { this.state = STATE_RELEASE; + Entities.editEntity(this.grabbedEntity, {gravity: this.saveGravity}); return; } From c8aea675057a0ed74193a1673ca054eda58ea394 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 2 Oct 2015 19:09:43 -0700 Subject: [PATCH 28/56] Working on texture compatibility with Shadertoy --- libraries/gpu/src/gpu/Texture.cpp | 19 ++++++++++++++++--- .../procedural/src/procedural/Procedural.cpp | 14 +++++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index d358b6431d..ae6f3b740d 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -343,9 +343,22 @@ bool Texture::assignStoredMipFace(uint16 level, const Element& format, Size size } uint16 Texture::autoGenerateMips(uint16 maxMip) { - _autoGenerateMips = true; - _maxMip = std::min((uint16) (evalNumMips() - 1), maxMip); - _stamp++; + bool changed = false; + if (!_autoGenerateMips) { + changed = true; + _autoGenerateMips = true; + } + + auto newMaxMip = std::min((uint16)(evalNumMips() - 1), maxMip); + if (newMaxMip != _maxMip) { + changed = true; + _maxMip = newMaxMip;; + } + + if (changed) { + _stamp++; + } + return _maxMip; } diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 18b6765d89..f5448bda5c 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -223,9 +223,21 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm lambda(batch); } + static gpu::Sampler sampler; + static std::once_flag once; + std::call_once(once, [&] { + gpu::Sampler::Desc desc; + desc._filter = gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR; + }); + for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { if (_channels[i] && _channels[i]->isLoaded()) { - batch.setResourceTexture(i, _channels[i]->getGPUTexture()); + auto gpuTexture = _channels[i]->getGPUTexture(); + if (gpuTexture) { + gpuTexture->setSampler(sampler); + gpuTexture->autoGenerateMips(-1); + } + batch.setResourceTexture(i, gpuTexture); } } } From 510065fe5c98a09892ccd9115eaec348f5d4a94e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 3 Oct 2015 09:16:07 -0700 Subject: [PATCH 29/56] Fix particle property maxParticles not being able to be set properly --- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/ParticleEffectEntityItem.cpp | 10 +++++----- libraries/entities/src/ParticleEffectEntityItem.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 61e369cf96..37e61ec0de 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -851,7 +851,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_TEXT_COLOR, TextColor, textColor, xColor); ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor); ADD_PROPERTY_TO_MAP(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); - ADD_PROPERTY_TO_MAP(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32); + ADD_PROPERTY_TO_MAP(PROP_MAX_PARTICLES, MaxParticles, maxParticles, float); ADD_PROPERTY_TO_MAP(PROP_LIFESPAN, Lifespan, lifespan, float); ADD_PROPERTY_TO_MAP(PROP_EMIT_RATE, EmitRate, emitRate, float); ADD_PROPERTY_TO_MAP(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, glm::vec3); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 55be145d85..e5aa40abc5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -138,7 +138,7 @@ public: DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor); DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor); DEFINE_PROPERTY_REF_ENUM(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); - DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32); + DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, float); DEFINE_PROPERTY(PROP_LIFESPAN, Lifespan, lifespan, float); DEFINE_PROPERTY(PROP_EMIT_RATE, EmitRate, emitRate, float); DEFINE_PROPERTY(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, float); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 3a823ae2e8..ddff80b1b5 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -354,7 +354,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch } READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType); - READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); + READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, float, setMaxParticles); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { @@ -878,10 +878,10 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } } -void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { - maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES); - if (_maxParticles != maxParticles) { - _maxParticles = maxParticles; +void ParticleEffectEntityItem::setMaxParticles(float maxParticles) { + maxParticles = glm::clamp(maxParticles, (float)MINIMUM_MAX_PARTICLES, (float)MAXIMUM_MAX_PARTICLES); + if (_maxParticles != (quint32)maxParticles) { + _maxParticles = (quint32)maxParticles; // TODO: try to do something smart here and preserve the state of existing particles. diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 30f899aac4..14b60ce4e2 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -123,8 +123,8 @@ public: static const quint32 DEFAULT_MAX_PARTICLES; static const quint32 MINIMUM_MAX_PARTICLES; static const quint32 MAXIMUM_MAX_PARTICLES; - void setMaxParticles(quint32 maxParticles); - quint32 getMaxParticles() const { return _maxParticles; } + void setMaxParticles(float maxParticles); + float getMaxParticles() const { return (float)_maxParticles; } static const float DEFAULT_LIFESPAN; static const float MINIMUM_LIFESPAN; From 53e85e8566f02e59249a473274fd05db1eca5006 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 3 Oct 2015 09:59:33 -0700 Subject: [PATCH 30/56] Tidying --- libraries/entities/src/ParticleEffectEntityItem.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index ddff80b1b5..0c187cfd1c 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -1,4 +1,3 @@ - // // ParticleEffectEntityItem.cpp // libraries/entities/src @@ -31,8 +30,6 @@ #include #include -#include - #include #include #include @@ -68,7 +65,7 @@ const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f; const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f; const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 343.2f; // Speed of sound +const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3 const float ParticleEffectEntityItem::DEFAULT_SPEED_SPREAD = 1.0f; const glm::quat ParticleEffectEntityItem::DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, X_AXIS); // Vertical const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIMENSIONS = glm::vec3(0.0f, 0.0f, 0.0f); // Emit from point From 725ed26ac2e72bf59f320151c93a226dcc039c19 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 4 Oct 2015 16:26:06 -0700 Subject: [PATCH 31/56] Enabling programmatic access to the IPD scale --- examples/example/hmd/ipdScalingTest.js | 42 ++++++++++++ interface/src/Application.cpp | 47 +++++++++---- interface/src/PluginContainerProxy.cpp | 7 ++ interface/src/PluginContainerProxy.h | 3 + interface/src/avatar/MyAvatar.cpp | 10 +-- .../src/scripting/HMDScriptingInterface.cpp | 68 ++++++++++--------- .../src/scripting/HMDScriptingInterface.h | 23 +++---- .../AbstractHMDScriptingInterface.cpp | 52 ++++++++++++++ .../AbstractHMDScriptingInterface.h | 39 +++++++++++ .../src/display-plugins/DisplayPlugin.h | 17 +++-- .../oculus/OculusBaseDisplayPlugin.cpp | 16 +++-- .../oculus/OculusBaseDisplayPlugin.h | 11 +-- .../display-plugins/oculus/OculusHelpers.h | 8 +++ .../oculus/OculusLegacyDisplayPlugin.cpp | 4 +- .../oculus/OculusLegacyDisplayPlugin.h | 2 +- .../openvr/OpenVrDisplayPlugin.cpp | 4 +- .../openvr/OpenVrDisplayPlugin.h | 2 +- .../stereo/StereoDisplayPlugin.cpp | 4 -- .../stereo/StereoDisplayPlugin.h | 9 ++- .../plugins/src/plugins/PluginContainer.cpp | 10 +++ .../plugins/src/plugins/PluginContainer.h | 4 ++ 21 files changed, 291 insertions(+), 91 deletions(-) create mode 100644 examples/example/hmd/ipdScalingTest.js create mode 100644 libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp create mode 100644 libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h diff --git a/examples/example/hmd/ipdScalingTest.js b/examples/example/hmd/ipdScalingTest.js new file mode 100644 index 0000000000..daa11170e4 --- /dev/null +++ b/examples/example/hmd/ipdScalingTest.js @@ -0,0 +1,42 @@ +// +// Created by Bradley Austin Davis on 2015/10/04 +// Copyright 2013-2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +IPDScalingTest = function() { + // Switch every 5 seconds between normal IPD and 0 IPD (in seconds) + this.UPDATE_INTERVAL = 10.0; + this.lastUpdateInterval = 0; + this.scaled = false; + + var that = this; + Script.scriptEnding.connect(function() { + that.onCleanup(); + }); + + Script.update.connect(function(deltaTime) { + that.lastUpdateInterval += deltaTime; + if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) { + that.onUpdate(that.lastUpdateInterval); + that.lastUpdateInterval = 0; + } + }); +} + +IPDScalingTest.prototype.onCleanup = function() { + HMD.setIPDScale(1.0); +} + +IPDScalingTest.prototype.onUpdate = function(deltaTime) { + this.scaled = !this.scaled; + if (this.scaled) { + HMD.ipdScale = 0.0; + } else { + HMD.ipdScale = 1.0; + } +} + +new IPDScalingTest(); \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b25f3aa6a5..025e448e29 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -300,6 +300,7 @@ bool setupEssentials(int& argc, char** argv) { auto desktopScriptingInterface = DependencyManager::set(); auto entityScriptingInterface = DependencyManager::set(); auto windowScriptingInterface = DependencyManager::set(); + auto hmdScriptingInterface = DependencyManager::set(); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::set(); #endif @@ -1203,9 +1204,11 @@ void Application::paintGL() { // right eye. There are FIXMEs in the relevant plugins _myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection())); renderArgs._context->enableStereo(true); - mat4 eyeViews[2]; + mat4 eyeOffsets[2]; mat4 eyeProjections[2]; auto baseProjection = renderArgs._viewFrustum->getProjection(); + auto hmdInterface = DependencyManager::get(); + float IPDScale = hmdInterface->getIPDScale(); // FIXME we probably don't need to set the projection matrix every frame, // only when the display plugin changes (or in non-HMD modes when the user // changes the FOV manually, which right now I don't think they can. @@ -1214,14 +1217,24 @@ void Application::paintGL() { // applied to the avatar, so we need to get the difference between the head // pose applied to the avatar and the per eye pose, and use THAT as // the per-eye stereo matrix adjustment. - mat4 eyePose = displayPlugin->getEyePose(eye); + mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye); + // Grab the translation + vec3 eyeOffset = glm::vec3(eyeToHead[3]); + // Apply IPD scaling + mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); + eyeOffsets[eye] = eyeOffsetTransform; + + // Tell the plugin what pose we're using to render. In this case we're just using the + // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it + // for rotational timewarp. If we move to support positonal timewarp, we need to + // ensure this contains the full pose composed with the eye offsets. mat4 headPose = displayPlugin->getHeadPose(); - mat4 eyeView = glm::inverse(eyePose) * headPose; - eyeViews[eye] = eyeView; + displayPlugin->setEyeRenderPose(eye, headPose); + eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection); }); renderArgs._context->setStereoProjections(eyeProjections); - renderArgs._context->setStereoViews(eyeViews); + renderArgs._context->setStereoViews(eyeOffsets); } displaySide(&renderArgs, _myCamera); renderArgs._context->enableStereo(false); @@ -4130,7 +4143,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Paths", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("HMD", &HMDScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("HMD", DependencyManager::get().data()); scriptEngine->registerFunction("HMD", "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0); scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0); @@ -4980,19 +4993,25 @@ mat4 Application::getEyeProjection(int eye) const { mat4 Application::getEyePose(int eye) const { if (isHMDMode()) { - return getActiveDisplayPlugin()->getEyePose((Eye)eye); + auto hmdInterface = DependencyManager::get(); + float IPDScale = hmdInterface->getIPDScale(); + auto displayPlugin = getActiveDisplayPlugin(); + mat4 headPose = displayPlugin->getHeadPose(); + mat4 eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye); + { + vec3 eyeOffset = glm::vec3(eyeToHead[3]); + // Apply IPD scaling + mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); + eyeToHead[3] = vec4(eyeOffset, 1.0); + } + return eyeToHead * headPose; } - return mat4(); } mat4 Application::getEyeOffset(int eye) const { - if (isHMDMode()) { - mat4 identity; - return getActiveDisplayPlugin()->getView((Eye)eye, identity); - } - - return mat4(); + // FIXME invert? + return getActiveDisplayPlugin()->getEyeToHeadTransform((Eye)eye); } mat4 Application::getHMDSensorPose() const { diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 4ef755bd1b..fd57b388fc 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -16,6 +16,9 @@ PluginContainerProxy::PluginContainerProxy() { Plugin::setContainer(this); } +PluginContainerProxy::~PluginContainerProxy() { +} + bool PluginContainerProxy::isForeground() { return qApp->_isForeground && !qApp->getWindow()->isMinimized(); } @@ -147,3 +150,7 @@ void PluginContainerProxy::showDisplayPluginsTools() { QGLWidget* PluginContainerProxy::getPrimarySurface() { return qApp->_glWidget; } + +const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const { + return qApp->getActiveDisplayPlugin(); +} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index e01cabc3b8..e3be5441b9 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -11,6 +11,7 @@ class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); + virtual ~PluginContainerProxy(); virtual void addMenu(const QString& menuName) override; virtual void removeMenu(const QString& menuName) override; virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; @@ -22,6 +23,8 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual void showDisplayPluginsTools() override; virtual QGLWidget* getPrimarySurface() override; virtual bool isForeground() override; + virtual const DisplayPlugin* getActiveDisplayPlugin() const override; + QRect _savedGeometry{ 10, 120, 800, 600 }; friend class Application; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9654305d70..71698fa4ea 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1341,11 +1341,13 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (qApp->isHMDMode()) { glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); - glm::mat4 leftEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyePose(Eye::Left); - glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]); - glm::mat4 rightEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyePose(Eye::Right); - glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]); glm::mat4 headPose = Application::getInstance()->getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 leftEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left); + leftEyePose = leftEyePose * headPose; + glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]); + glm::mat4 rightEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right); + rightEyePose = rightEyePose * headPose; + glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]); glm::vec3 headPosition = glm::vec3(headPose[3]); getHead()->renderLookAts(renderArgs, diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 68ac511eaf..f6bf7f8b3c 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -10,12 +10,46 @@ // #include "HMDScriptingInterface.h" + +#include + #include "display-plugins/DisplayPlugin.h" #include +#include "Application.h" -HMDScriptingInterface& HMDScriptingInterface::getInstance() { - static HMDScriptingInterface sharedInstance; - return sharedInstance; +HMDScriptingInterface::HMDScriptingInterface() { +} + +QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { + glm::vec3 hudIntersection; + auto instance = DependencyManager::get(); + if (instance->getHUDLookAtPosition3D(hudIntersection)) { + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition(); + glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); + glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); + glm::vec3 eulers = ::safeEulerAngles(rotation); + return qScriptValueFromValue(engine, Application::getInstance()->getApplicationCompositor() + .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); + } + return QScriptValue::NullValue; +} + +QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) { + glm::vec3 result; + auto instance = DependencyManager::get(); + if (instance->getHUDLookAtPosition3D(result)) { + return qScriptValueFromValue(engine, result); + } + return QScriptValue::NullValue; +} + +void HMDScriptingInterface::toggleMagnifier() { + qApp->getApplicationCompositor().toggleMagnifier(); +} + +bool HMDScriptingInterface::getMagnifier() const { + return Application::getInstance()->getApplicationCompositor().hasMagnifier(); } bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { @@ -29,31 +63,3 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { return compositor.calculateRayUICollisionPoint(position, direction, result); } - -QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { - - glm::vec3 hudIntersection; - - if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(hudIntersection)) { - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition(); - glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); - glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); - glm::vec3 eulers = ::safeEulerAngles(rotation); - return qScriptValueFromValue(engine, Application::getInstance()->getApplicationCompositor() - .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); - } - return QScriptValue::NullValue; -} - -QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) { - glm::vec3 result; - if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(result)) { - return qScriptValueFromValue(engine, result); - } - return QScriptValue::NullValue; -} - -float HMDScriptingInterface::getIPD() const { - return Application::getInstance()->getActiveDisplayPlugin()->getIPD(); -} diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 82b444abaa..c097cde5e3 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -12,32 +12,29 @@ #ifndef hifi_HMDScriptingInterface_h #define hifi_HMDScriptingInterface_h +#include +class QScriptContext; +class QScriptEngine; + #include +#include +#include -#include "Application.h" -class HMDScriptingInterface : public QObject { +class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency { Q_OBJECT Q_PROPERTY(bool magnifier READ getMagnifier) - Q_PROPERTY(bool active READ isHMDMode) - Q_PROPERTY(float ipd READ getIPD) public: - static HMDScriptingInterface& getInstance(); - + HMDScriptingInterface(); static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine); static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); public slots: - void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); }; + void toggleMagnifier(); private: - HMDScriptingInterface() {}; - bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); }; - bool isHMDMode() const { return Application::getInstance()->isHMDMode(); } - float getIPD() const; - + bool getMagnifier() const; bool getHUDLookAtPosition3D(glm::vec3& result) const; - }; #endif // hifi_HMDScriptingInterface_h diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp new file mode 100644 index 0000000000..9987ae345c --- /dev/null +++ b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp @@ -0,0 +1,52 @@ +// +// Created by Bradley Austin Davis on 2015/10/04 +// Copyright 2013-2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AbstractHMDScriptingInterface.h" + +#include + +#include "DisplayPlugin.h" +#include +#include + +static Setting::Handle IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f); + +AbstractHMDScriptingInterface::AbstractHMDScriptingInterface() { + _IPDScale = IPD_SCALE_HANDLE.get(); +} + +float AbstractHMDScriptingInterface::getIPD() const { + return PluginContainer::getInstance().getActiveDisplayPlugin()->getIPD(); +} + +float AbstractHMDScriptingInterface::getEyeHeight() const { + // FIXME update the display plugin interface to expose per-plugin settings + return OVR_DEFAULT_EYE_HEIGHT; +} + +float AbstractHMDScriptingInterface::getPlayerHeight() const { + // FIXME update the display plugin interface to expose per-plugin settings + return OVR_DEFAULT_PLAYER_HEIGHT; +} + +float AbstractHMDScriptingInterface::getIPDScale() const { + return _IPDScale; +} + +void AbstractHMDScriptingInterface::setIPDScale(float IPDScale) { + IPDScale = glm::clamp(IPDScale, -1.0f, 3.0f); + if (IPDScale != _IPDScale) { + _IPDScale = IPDScale; + IPD_SCALE_HANDLE.set(IPDScale); + emit IPDScaleChanged(); + } +} + +bool AbstractHMDScriptingInterface::isHMDMode() const { + return PluginContainer::getInstance().getActiveDisplayPlugin()->isHmd(); +} diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h new file mode 100644 index 0000000000..5df58ce677 --- /dev/null +++ b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h @@ -0,0 +1,39 @@ +// +// Created by Bradley Austin Davis on 2015/10/04 +// Copyright 2013-2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_AbstractHMDScriptingInterface_h +#define hifi_AbstractHMDScriptingInterface_h + +#include + +class AbstractHMDScriptingInterface : public QObject { + Q_OBJECT + Q_PROPERTY(bool active READ isHMDMode) + Q_PROPERTY(float ipd READ getIPD) + Q_PROPERTY(float eyeHeight READ getEyeHeight) + Q_PROPERTY(float playerHeight READ getPlayerHeight) + Q_PROPERTY(float ipdScale READ getIPDScale WRITE setIPDScale NOTIFY IPDScaleChanged) + +public: + AbstractHMDScriptingInterface(); + float getIPD() const; + float getEyeHeight() const; + float getPlayerHeight() const; + float getIPDScale() const; + void setIPDScale(float ipdScale); + bool isHMDMode() const; + +signals: + void IPDScaleChanged(); + +private: + float _IPDScale{ 1.0 }; +}; + +#endif // hifi_AbstractHMDScriptingInterface_h diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h index 8b9d249bd4..b4ae6be97f 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h @@ -46,6 +46,8 @@ void for_each_eye(F f, FF ff) { class QWindow; +#define AVERAGE_HUMAN_IPD 0.064f + class DisplayPlugin : public Plugin { Q_OBJECT public: @@ -107,21 +109,22 @@ public: return baseProjection; } - virtual glm::mat4 getView(Eye eye, const glm::mat4& baseView) const { - return glm::inverse(getEyePose(eye)) * baseView; - } - // HMD specific methods // TODO move these into another class? - virtual glm::mat4 getEyePose(Eye eye) const { - static const glm::mat4 pose; return pose; + virtual glm::mat4 getEyeToHeadTransform(Eye eye) const { + static const glm::mat4 transform; return transform; } virtual glm::mat4 getHeadPose() const { static const glm::mat4 pose; return pose; } - virtual float getIPD() const { return 0.0f; } + // Needed for timewarp style features + virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) { + // NOOP + } + + virtual float getIPD() const { return AVERAGE_HUMAN_IPD; } virtual void abandonCalibration() {} virtual void resetSensors() {} diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp index f2a7b06510..859a4a810a 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp @@ -19,7 +19,6 @@ void OculusBaseDisplayPlugin::preRender() { #if (OVR_MAJOR_VERSION >= 6) ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex); _trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds); - ovr_CalcEyePoses(_trackingState.HeadPose.ThePose, _eyeOffsets, _eyePoses); #endif } @@ -33,14 +32,19 @@ void OculusBaseDisplayPlugin::resetSensors() { #endif } -glm::mat4 OculusBaseDisplayPlugin::getEyePose(Eye eye) const { - return toGlm(_eyePoses[eye]); +glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const { + return glm::translate(mat4(), toGlm(_eyeOffsets[eye])); } glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const { return toGlm(_trackingState.HeadPose.ThePose); } +void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) { + _eyePoses[eye] = ovrPoseFromGlm(pose); +} + + bool OculusBaseDisplayPlugin::isSupported() const { #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { @@ -151,9 +155,9 @@ void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sce } float OculusBaseDisplayPlugin::getIPD() const { - float result = 0.0f; + float result = OVR_DEFAULT_IPD; #if (OVR_MAJOR_VERSION >= 6) - result = ovr_GetFloat(_hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD); + result = ovr_GetFloat(_hmd, OVR_KEY_IPD, result); #endif return result; -} \ No newline at end of file +} diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h index d879085b8f..6307f6bbf9 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h @@ -29,8 +29,9 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override final; virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); } virtual void resetSensors() override final; - virtual glm::mat4 getEyePose(Eye eye) const override final; + virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final; virtual glm::mat4 getHeadPose() const override final; + virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final; virtual float getIPD() const override final; protected: @@ -39,6 +40,7 @@ protected: protected: ovrPosef _eyePoses[2]; + ovrVector3f _eyeOffsets[2]; mat4 _eyeProjections[3]; mat4 _compositeEyeProjections[2]; @@ -50,13 +52,12 @@ protected: ovrHmd _hmd; float _ipd{ OVR_DEFAULT_IPD }; ovrEyeRenderDesc _eyeRenderDescs[2]; - ovrVector3f _eyeOffsets[2]; ovrFovPort _eyeFovs[2]; - ovrHmdDesc _hmdDesc; - ovrLayerEyeFov _sceneLayer; + ovrHmdDesc _hmdDesc; + ovrLayerEyeFov _sceneLayer; #endif #if (OVR_MAJOR_VERSION == 7) - ovrGraphicsLuid _luid; + ovrGraphicsLuid _luid; #endif }; diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h b/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h index df0a6c5228..5a6999075b 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h @@ -79,3 +79,11 @@ inline ovrQuatf ovrFromGlm(const glm::quat & q) { return{ q.x, q.y, q.z, q.w }; } +inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) { + glm::vec3 translation = glm::vec3(m[3]) / m[3].w; + glm::quat orientation = glm::quat_cast(m); + ovrPosef result; + result.Orientation = ovrFromGlm(orientation); + result.Position = ovrFromGlm(translation); + return result; +} diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp index ade34afcae..1ad61513d6 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp @@ -59,11 +59,11 @@ void OculusLegacyDisplayPlugin::resetSensors() { #endif } -glm::mat4 OculusLegacyDisplayPlugin::getEyePose(Eye eye) const { +glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const { #if (OVR_MAJOR_VERSION == 5) return toGlm(_eyePoses[eye]); #else - return WindowOpenGLDisplayPlugin::getEyePose(eye); + return WindowOpenGLDisplayPlugin::getEyeToHeadTransform(eye); #endif } diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h index 5bce032948..9e2e47f434 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h @@ -31,7 +31,7 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override; virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); } virtual void resetSensors() override; - virtual glm::mat4 getEyePose(Eye eye) const override; + virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; virtual glm::mat4 getHeadPose() const override; protected: diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index fab9cc5dd4..faf5a7b781 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -160,8 +160,8 @@ void OpenVrDisplayPlugin::resetSensors() { _sensorResetMat = glm::inverse(cancelOutRollAndPitch(_trackedDevicePoseMat4[0])); } -glm::mat4 OpenVrDisplayPlugin::getEyePose(Eye eye) const { - return getHeadPose() * _eyesData[eye]._eyeOffset; +glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const { + return _eyesData[eye]._eyeOffset; } glm::mat4 OpenVrDisplayPlugin::getHeadPose() const { diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h index afe024e72b..7849623552 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h @@ -29,7 +29,7 @@ public: virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; virtual void resetSensors() override; - virtual glm::mat4 getEyePose(Eye eye) const override; + virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; virtual glm::mat4 getHeadPose() const override; protected: diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index 77906d1857..2ea79ed2e0 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -61,10 +61,6 @@ glm::mat4 StereoDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProje return eyeProjection; } -glm::mat4 StereoDisplayPlugin::getEyePose(Eye eye) const { - return mat4(); -} - std::vector _screenActions; void StereoDisplayPlugin::activate() { auto screens = qApp->screens(); diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h index 86f35c1260..33b0b09b0d 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h @@ -21,7 +21,14 @@ public: virtual float getRecommendedAspectRatio() const override; virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; - virtual glm::mat4 getEyePose(Eye eye) const override; + + // NOTE, because Stereo displays don't include head tracking, and therefore + // can't include roll or pitch, the eye separation is embedded into the projection + // matrix. However, this eliminates the possibility of easily mainpulating + // the IPD at the Application level, the way we now allow with HMDs. + // If that becomes an issue then we'll need to break up the functionality similar + // to the HMD plugins. + // virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; protected: void updateScreen(); diff --git a/libraries/plugins/src/plugins/PluginContainer.cpp b/libraries/plugins/src/plugins/PluginContainer.cpp index b27f076eb6..8afac745f3 100644 --- a/libraries/plugins/src/plugins/PluginContainer.cpp +++ b/libraries/plugins/src/plugins/PluginContainer.cpp @@ -9,7 +9,17 @@ static PluginContainer* INSTANCE{ nullptr }; +PluginContainer& PluginContainer::getInstance() { + Q_ASSERT(INSTANCE); + return *INSTANCE; +} + PluginContainer::PluginContainer() { Q_ASSERT(!INSTANCE); INSTANCE = this; }; + +PluginContainer::~PluginContainer() { + Q_ASSERT(INSTANCE == this); + INSTANCE = nullptr; +}; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index c2cba23392..f52799adb3 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -13,10 +13,13 @@ class QAction; class QGLWidget; class QScreen; +class DisplayPlugin; class PluginContainer { public: + static PluginContainer& getInstance(); PluginContainer(); + virtual ~PluginContainer(); virtual void addMenu(const QString& menuName) = 0; virtual void removeMenu(const QString& menuName) = 0; virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; @@ -28,4 +31,5 @@ public: virtual void showDisplayPluginsTools() = 0; virtual QGLWidget* getPrimarySurface() = 0; virtual bool isForeground() = 0; + virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; }; From 65ae811c9c50a4200d85686f1d0d40f1ec02da76 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 5 Oct 2015 11:16:55 -0700 Subject: [PATCH 32/56] make ping pong balls bigger and slower, change out gun model and adjust tip calculations, increase volume, add to master reset script --- .../toys/ping_pong_gun/createPingPongGun.js | 5 +++-- examples/toys/ping_pong_gun/pingPongGun.js | 17 ++++++++--------- unpublishedScripts/masterReset.js | 5 +---- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/examples/toys/ping_pong_gun/createPingPongGun.js b/examples/toys/ping_pong_gun/createPingPongGun.js index 4969a0bc72..cf56d6f790 100644 --- a/examples/toys/ping_pong_gun/createPingPongGun.js +++ b/examples/toys/ping_pong_gun/createPingPongGun.js @@ -25,8 +25,9 @@ var center = Vec3.sum(Vec3.sum(MyAvatar.position, { var pingPongGun = Entities.addEntity({ type: "Model", modelURL: MODEL_URL, - shapeType: 'compound', - compoundShapeURL: COLLISION_HULL_URL, + shapeType:'box', + // shapeType: 'compound', + // compoundShapeURL: COLLISION_HULL_URL, script: scriptURL, position: center, dimensions: { diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toys/ping_pong_gun/pingPongGun.js index 298d93a523..1b5973c8bb 100644 --- a/examples/toys/ping_pong_gun/pingPongGun.js +++ b/examples/toys/ping_pong_gun/pingPongGun.js @@ -21,14 +21,14 @@ //if the trigger value goes below this value, reload the gun. var RELOAD_THRESHOLD = 0.95; - var GUN_TIP_FWD_OFFSET = 0.45; + var GUN_TIP_FWD_OFFSET =-0.35; var GUN_TIP_UP_OFFSET = 0.040; - var GUN_FORCE = 8; + var GUN_FORCE = 9; var BALL_RESTITUTION = 0.6; var BALL_LINEAR_DAMPING = 0.4; var BALL_GRAVITY = { x: 0, - y: -5.8, + y: -4.8, z: 0 }; @@ -68,7 +68,6 @@ }, continueNearGrab: function() { - if (this.whichHand === null) { //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten this.setWhichHand(); @@ -111,7 +110,7 @@ }, shootBall: function(gunProperties) { - var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, -90, 0))); + var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, 180, 0))); forwardVec = Vec3.normalize(forwardVec); forwardVec = Vec3.multiply(forwardVec, GUN_FORCE); @@ -136,7 +135,7 @@ playSoundAtCurrentPosition: function(position) { var audioProperties = { - volume: 0.1, + volume: 0.2, position: position }; @@ -145,11 +144,11 @@ getGunTipPosition: function(properties) { //the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position - var frontVector = Quat.getRight(properties.rotation); + var frontVector = Quat.getFront(properties.rotation); var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET); - var upVector = Quat.getRight(properties.rotation); + var upVector = Quat.getUp(properties.rotation); var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET); - + var gunTipPosition = Vec3.sum(properties.position, frontOffset); gunTipPosition = Vec3.sum(gunTipPosition, upOffset); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 13445ca438..a3d4bcc70d 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -457,8 +457,7 @@ function createPingPongBallGun() { var pingPongGun = Entities.addEntity({ type: "Model", modelURL: MODEL_URL, - shapeType: 'compound', - compoundShapeURL: COLLISION_HULL_URL, + shapeType: 'box', script: scriptURL, position: position, rotation: rotation, @@ -478,8 +477,6 @@ function createPingPongBallGun() { setEntityCustomData(resetKey, pingPongGun, { resetMe: true }); - - } function createBasketballHoop() { From 993111d22f6249b788c4ca37f51dce9ca85d63ee Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 5 Oct 2015 11:28:59 -0700 Subject: [PATCH 33/56] code review --- interface/src/InterfaceActionFactory.cpp | 6 +++--- libraries/entities/src/EntityItem.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/InterfaceActionFactory.cpp b/interface/src/InterfaceActionFactory.cpp index 2879c19eaa..cf5dad8fa5 100644 --- a/interface/src/InterfaceActionFactory.cpp +++ b/interface/src/InterfaceActionFactory.cpp @@ -65,9 +65,9 @@ EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEnt if (action) { action->deserialize(data); - } - if (action->lifetimeIsOver()) { - return nullptr; + if (action->lifetimeIsOver()) { + return nullptr; + } } return action; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a031fbb196..c4f5ad0061 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1661,13 +1661,14 @@ void EntityItem::deserializeActionsInternal() { // TODO: make sure types match? there isn't currently a way to // change the type of an existing action. action->deserialize(serializedAction); + action->locallyAddedButNotYetReceived = false; } else { auto actionFactory = DependencyManager::get(); EntityItemPointer entity = shared_from_this(); EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { - action->locallyAddedButNotYetReceived = false; entity->addActionInternal(simulation, action); + action->locallyAddedButNotYetReceived = false; } } } From 75849db86729f7cd4382e149a60940df9314737a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 5 Oct 2015 12:00:02 -0700 Subject: [PATCH 34/56] Changed (float)fabs() to fabsf() --- libraries/animation/src/AnimClip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index 0d181f8e47..251cb0047a 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -159,7 +159,7 @@ void AnimClip::copyFromNetworkAnim() { // used to adjust translation offsets, so large translation animatons on the reference skeleton // will be adjusted when played on a skeleton with short limbs. - float limbLengthScale = (float)fabs(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans)); + float limbLengthScale = fabsf(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans)); AnimPose& pose = _anim[frame][skeletonJoint]; const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame]; From 844270e3060048b54ad419a9ea3cbdfb97813bdb Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 5 Oct 2015 12:44:22 -0700 Subject: [PATCH 35/56] Reset (as though by apostrophe key) whenever we calibrate the hydra. --- interface/src/PluginContainerProxy.cpp | 4 ++++ interface/src/PluginContainerProxy.h | 1 + libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 1 + libraries/plugins/src/plugins/PluginContainer.h | 1 + 4 files changed, 7 insertions(+) diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 4ef755bd1b..469e7f7c77 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -139,6 +139,10 @@ void PluginContainerProxy::unsetFullscreen(const QScreen* avoid) { #endif } +void PluginContainerProxy::requestReset() { + // We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway. + qApp->resetSensors(); +} void PluginContainerProxy::showDisplayPluginsTools() { DependencyManager::get()->hmdTools(true); diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index e01cabc3b8..6910dbcd47 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -20,6 +20,7 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override; virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override; virtual void showDisplayPluginsTools() override; + virtual void requestReset() override; virtual QGLWidget* getPrimarySurface() override; virtual bool isForeground() override; QRect _savedGeometry{ 10, 120, 800, 600 }; diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index aa04c49adb..e900e8779e 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -285,6 +285,7 @@ void SixenseManager::updateCalibration(void* controllersX) { _avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis))); const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f; _avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR; + CONTAINER->requestReset(); qCDebug(inputplugins, "succeess: sixense calibration"); } break; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index c2cba23392..f938758161 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -26,6 +26,7 @@ public: virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = false) = 0; virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; virtual void showDisplayPluginsTools() = 0; + virtual void requestReset() = 0; virtual QGLWidget* getPrimarySurface() = 0; virtual bool isForeground() = 0; }; From 7f84e882c5537591184d897b9163bbe861a6a8c3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 5 Oct 2015 13:06:39 -0700 Subject: [PATCH 36/56] attempt to keep ignoreForCollisions the same before and after grab --- examples/controllers/handControllerGrab.js | 23 ++++++++++++++++++---- examples/libraries/utils.js | 6 +++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d143df1e83..eba69c2150 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -81,6 +81,8 @@ var STATE_RELEASE = 8; var GRAB_USER_DATA_KEY = "grabKey"; var GRABBABLE_DATA_KEY = "grabbableKey"; +var GRAVITY_USER_DATA_KEY = "preGrabGravity"; +var IGNORE_FOR_COLLISIONS_USER_DATA_KEY = "preGrabIgnoreForCollisions"; function getTag() { return "grab-" + MyAvatar.sessionUUID; @@ -431,7 +433,8 @@ function MyController(hand, triggerAction) { this.activateEntity(this.grabbedEntity); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", "gravity"]); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, + ["position", "rotation", "gravity", "ignoreForCollisions"]); var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); @@ -443,8 +446,17 @@ function MyController(hand, triggerAction) { var offset = Vec3.subtract(currentObjectPosition, handPosition); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); - this.saveGravity = grabbedProperties.gravity; - Entities.editEntity(this.grabbedEntity, {gravity: {x:0, y:0, z:0}}); + // zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done + this.saveGravity = getEntityCustomData(GRAVITY_USER_DATA_KEY, this.grabbedEntity, grabbedProperties.gravity); + setEntityCustomData(GRAVITY_USER_DATA_KEY, this.grabbedEntity, this.saveGravity); + + this.saveIgnoreForCollisions = getEntityCustomData(IGNORE_FOR_COLLISIONS_USER_DATA_KEY, this.grabbedEntity, + grabbedProperties.ignoreForCollisions); + setEntityCustomData(IGNORE_FOR_COLLISIONS_USER_DATA_KEY, this.grabbedEntity, this.saveIgnoreForCollisions); + + print("this.ifc = " + this.saveIgnoreForCollisions + ", props.ifc = " + grabbedProperties.ignoreForCollisions); + + Entities.editEntity(this.grabbedEntity, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true}); this.actionID = NULL_ACTION_ID; this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, { @@ -475,7 +487,10 @@ function MyController(hand, triggerAction) { this.continueNearGrabbing = function() { if (this.triggerSmoothedReleased()) { this.state = STATE_RELEASE; - Entities.editEntity(this.grabbedEntity, {gravity: this.saveGravity}); + Entities.editEntity(this.grabbedEntity, + {gravity: this.saveGravity, ignoreForCollisions: this.saveIgnoreForCollisions}); + setEntityCustomData(IGNORE_FOR_COLLISIONS_USER_DATA_KEY, this.grabbedEntity, null); + setEntityCustomData(GRAVITY_USER_DATA_KEY, this.grabbedEntity, null); return; } diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index fa0f36cbb1..f876d48777 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -79,7 +79,11 @@ getEntityUserData = function(id) { // Non-destructively modify the user data of an entity. setEntityCustomData = function(customKey, id, data) { var userData = getEntityUserData(id); - userData[customKey] = data; + if (data == null) { + delete userData[customKey]; + } else { + userData[customKey] = data; + } setEntityUserData(id, userData); } From c72c87b59c3be8ae4af9618d6c2e3fe42d347d5f Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Mon, 5 Oct 2015 13:35:58 -0700 Subject: [PATCH 37/56] Revert "QA for 20699 - Sanitize particle property values when set" --- .../entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityItemProperties.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 124 ++++-------------- .../entities/src/ParticleEffectEntityItem.h | 62 +++------ 4 files changed, 42 insertions(+), 148 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 37e61ec0de..61e369cf96 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -851,7 +851,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_TEXT_COLOR, TextColor, textColor, xColor); ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor); ADD_PROPERTY_TO_MAP(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); - ADD_PROPERTY_TO_MAP(PROP_MAX_PARTICLES, MaxParticles, maxParticles, float); + ADD_PROPERTY_TO_MAP(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32); ADD_PROPERTY_TO_MAP(PROP_LIFESPAN, Lifespan, lifespan, float); ADD_PROPERTY_TO_MAP(PROP_EMIT_RATE, EmitRate, emitRate, float); ADD_PROPERTY_TO_MAP(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, glm::vec3); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index e5aa40abc5..55be145d85 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -138,7 +138,7 @@ public: DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor); DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor); DEFINE_PROPERTY_REF_ENUM(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); - DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, float); + DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32); DEFINE_PROPERTY(PROP_LIFESPAN, Lifespan, lifespan, float); DEFINE_PROPERTY(PROP_EMIT_RATE, EmitRate, emitRate, float); DEFINE_PROPERTY(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, float); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 0c187cfd1c..40d3853c39 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -1,3 +1,4 @@ + // // ParticleEffectEntityItem.cpp // libraries/entities/src @@ -30,6 +31,8 @@ #include #include +#include + #include #include #include @@ -49,48 +52,24 @@ const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f; const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA; const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA; -const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f; const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000; -const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1; -const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000; const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f; -const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f; -const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f; const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f; -const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3 const float ParticleEffectEntityItem::DEFAULT_SPEED_SPREAD = 1.0f; const glm::quat ParticleEffectEntityItem::DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, X_AXIS); // Vertical const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIMENSIONS = glm::vec3(0.0f, 0.0f, 0.0f); // Emit from point -const float ParticleEffectEntityItem::MINIMUM_EMIT_DIMENSION = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_DIMENSION = (float)TREE_SCALE; const float ParticleEffectEntityItem::DEFAULT_EMIT_RADIUS_START = 1.0f; // Emit from surface (when emitDimensions > 0) -const float ParticleEffectEntityItem::MINIMUM_EMIT_RADIUS_START = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_RADIUS_START = 1.0f; -const float ParticleEffectEntityItem::MINIMUM_POLAR = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_POLAR = PI; const float ParticleEffectEntityItem::DEFAULT_POLAR_START = 0.0f; // Emit along z-axis const float ParticleEffectEntityItem::DEFAULT_POLAR_FINISH = 0.0f; // "" -const float ParticleEffectEntityItem::MINIMUM_AZIMUTH = -PI; -const float ParticleEffectEntityItem::MAXIMUM_AZIMUTH = PI; const float ParticleEffectEntityItem::DEFAULT_AZIMUTH_START = -PI; // Emit full circumference (when polarFinish > 0) const float ParticleEffectEntityItem::DEFAULT_AZIMUTH_FINISH = PI; // "" const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f); -const float ParticleEffectEntityItem::MINIMUM_EMIT_ACCELERATION = -100.0f; // ~ 10g -const float ParticleEffectEntityItem::MAXIMUM_EMIT_ACCELERATION = 100.0f; const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f); -const float ParticleEffectEntityItem::MINIMUM_ACCELERATION_SPREAD = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_ACCELERATION_SPREAD = 100.0f; const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f; -const float ParticleEffectEntityItem::MINIMUM_PARTICLE_RADIUS = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_PARTICLE_RADIUS = (float)TREE_SCALE; const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; @@ -135,82 +114,37 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() { } -void ParticleEffectEntityItem::setAlphaStart(float alphaStart) { - _alphaStart = glm::clamp(alphaStart, MINIMUM_ALPHA, MAXIMUM_ALPHA); - _isAlphaStartInitialized = true; -} - -void ParticleEffectEntityItem::setAlphaFinish(float alphaFinish) { - _alphaFinish = glm::clamp(alphaFinish, MINIMUM_ALPHA, MAXIMUM_ALPHA); - _isAlphaFinishInitialized = true; -} - void ParticleEffectEntityItem::setEmitSpeed(float emitSpeed) { - _emitSpeed = glm::clamp(emitSpeed, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED); + _emitSpeed = emitSpeed; computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setSpeedSpread(float speedSpread) { - _speedSpread = glm::clamp(speedSpread, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED); + _speedSpread = speedSpread; computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setEmitOrientation(const glm::quat& emitOrientation) { - _emitOrientation = glm::normalize(emitOrientation); + _emitOrientation = emitOrientation; computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setEmitDimensions(const glm::vec3& emitDimensions) { - _emitDimensions = glm::vec3( - glm::clamp(emitDimensions.x, MINIMUM_EMIT_DIMENSION, MAXIMUM_EMIT_DIMENSION), - glm::clamp(emitDimensions.y, MINIMUM_EMIT_DIMENSION, MAXIMUM_EMIT_DIMENSION), - glm::clamp(emitDimensions.z, MINIMUM_EMIT_DIMENSION, MAXIMUM_EMIT_DIMENSION) - ); + _emitDimensions = emitDimensions; computeAndUpdateDimensions(); } -void ParticleEffectEntityItem::setEmitRadiusStart(float emitRadiusStart) { - _emitRadiusStart = glm::clamp(emitRadiusStart, MINIMUM_EMIT_RADIUS_START, MAXIMUM_EMIT_RADIUS_START); -} - void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) { - _emitAcceleration = glm::vec3( - glm::clamp(emitAcceleration.x, MINIMUM_EMIT_ACCELERATION, MAXIMUM_EMIT_ACCELERATION), - glm::clamp(emitAcceleration.x, MINIMUM_EMIT_ACCELERATION, MAXIMUM_EMIT_ACCELERATION), - glm::clamp(emitAcceleration.y, MINIMUM_EMIT_ACCELERATION, MAXIMUM_EMIT_ACCELERATION) - ); + _emitAcceleration = emitAcceleration; computeAndUpdateDimensions(); } void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerationSpread){ - _accelerationSpread = glm::vec3( - glm::clamp(accelerationSpread.x, MINIMUM_ACCELERATION_SPREAD, MAXIMUM_ACCELERATION_SPREAD), - glm::clamp(accelerationSpread.x, MINIMUM_ACCELERATION_SPREAD, MAXIMUM_ACCELERATION_SPREAD), - glm::clamp(accelerationSpread.y, MINIMUM_ACCELERATION_SPREAD, MAXIMUM_ACCELERATION_SPREAD) - ); + _accelerationSpread = accelerationSpread; computeAndUpdateDimensions(); } -void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { - _particleRadius = glm::clamp(particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); -} - -void ParticleEffectEntityItem::setRadiusStart(float radiusStart) { - _radiusStart = glm::clamp(radiusStart, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - _isRadiusStartInitialized = true; -} - -void ParticleEffectEntityItem::setRadiusFinish(float radiusFinish) { - _radiusFinish = glm::clamp(radiusFinish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - _isRadiusFinishInitialized = true; -} - -void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) { - _radiusSpread = glm::clamp(radiusSpread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); -} - - void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error @@ -351,7 +285,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch } READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType); - READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, float, setMaxParticles); + READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { @@ -705,12 +639,12 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleLifetimes[i] -= deltaTime; // if particle has died. - if (_particleLifetimes[i] <= 0.0f || _lifespan == 0.0f) { + if (_particleLifetimes[i] <= 0.0f) { // move head forward _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; } else { - float age = 1.0f - _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0 + float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0 updateRadius(i, age); updateColor(i, age); updateAlpha(i, age); @@ -720,7 +654,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } // emit new particles, but only if animation is playing - if (getAnimationIsPlaying() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) { + if (getAnimationIsPlaying()) { float timeLeftInFrame = deltaTime; while (_timeUntilNextEmit < timeLeftInFrame) { @@ -738,18 +672,10 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _radiusMiddles[i] =_particleRadius; _radiusFinishes[i] = getRadiusFinish(); } else { - float spreadMultiplier; - if (_particleRadius > 0.0f) { - spreadMultiplier = 1.0f + (2.0f * randFloat() - 1.0f) * _radiusSpread / _particleRadius; - } else { - spreadMultiplier = 0.0f; - } - _radiusStarts[i] = - glm::clamp(spreadMultiplier * getRadiusStart(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - _radiusMiddles[i] = - glm::clamp(spreadMultiplier * _particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - _radiusFinishes[i] = - glm::clamp(spreadMultiplier * getRadiusFinish(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1.0f) * _radiusSpread / _particleRadius; + _radiusStarts[i] = spreadMultiplier * getRadiusStart(); + _radiusMiddles[i] = spreadMultiplier * _particleRadius; + _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); } updateRadius(i, 0.0f); @@ -827,12 +753,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { xColor finishColor = getColorFinish(); float spread = 2.0f * randFloat() - 1.0f; - float spreadMultiplierRed = - middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; - float spreadMultiplierGreen = - middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green :1.0f; - float spreadMultiplierBlue = - middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; + float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red; + float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green; + float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue; _colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); _colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); @@ -875,10 +798,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } } -void ParticleEffectEntityItem::setMaxParticles(float maxParticles) { - maxParticles = glm::clamp(maxParticles, (float)MINIMUM_MAX_PARTICLES, (float)MAXIMUM_MAX_PARTICLES); - if (_maxParticles != (quint32)maxParticles) { - _maxParticles = (quint32)maxParticles; +void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { + if (_maxParticles != maxParticles) { + _maxParticles = maxParticles; // TODO: try to do something smart here and preserve the state of existing particles. diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 14b60ce4e2..6d5b8761b0 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -12,7 +12,6 @@ #define hifi_ParticleEffectEntityItem_h #include - #include "EntityItem.h" class ParticleEffectEntityItem : public EntityItem { @@ -69,25 +68,22 @@ public: void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; } xColor getColorSpread() const { return _colorSpread; } - static const float MAXIMUM_ALPHA; - static const float MINIMUM_ALPHA; - static const float DEFAULT_ALPHA; - void setAlpha(float alpha) { _alpha = glm::clamp(alpha, MINIMUM_ALPHA, MAXIMUM_ALPHA); } + void setAlpha(float alpha) { _alpha = alpha; } float getAlpha() const { return _alpha; } static const float DEFAULT_ALPHA_START; bool _isAlphaStartInitialized = false; - void setAlphaStart(float alphaStart); + void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; } float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; } static const float DEFAULT_ALPHA_FINISH; bool _isAlphaFinishInitialized = false; - void setAlphaFinish(float alphaFinish); + void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; } float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; } static const float DEFAULT_ALPHA_SPREAD; - void setAlphaSpread(float alphaSpread) { _alphaSpread = glm::clamp(alphaSpread, MINIMUM_ALPHA, MAXIMUM_ALPHA); } + void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; } float getAlphaSpread() const { return _alphaSpread; } void updateShapeType(ShapeType type); @@ -121,26 +117,18 @@ public: float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } static const quint32 DEFAULT_MAX_PARTICLES; - static const quint32 MINIMUM_MAX_PARTICLES; - static const quint32 MAXIMUM_MAX_PARTICLES; - void setMaxParticles(float maxParticles); - float getMaxParticles() const { return (float)_maxParticles; } + void setMaxParticles(quint32 maxParticles); + quint32 getMaxParticles() const { return _maxParticles; } static const float DEFAULT_LIFESPAN; - static const float MINIMUM_LIFESPAN; - static const float MAXIMUM_LIFESPAN; - void setLifespan(float lifespan) { _lifespan = glm::clamp(lifespan, MINIMUM_LIFESPAN, MAXIMUM_LIFESPAN); } + void setLifespan(float lifespan) { _lifespan = lifespan; } float getLifespan() const { return _lifespan; } static const float DEFAULT_EMIT_RATE; - static const float MINIMUM_EMIT_RATE; - static const float MAXIMUM_EMIT_RATE; - void setEmitRate(float emitRate) { _emitRate = glm::clamp(emitRate, MINIMUM_EMIT_RATE, MAXIMUM_EMIT_RATE); } + void setEmitRate(float emitRate) { _emitRate = emitRate; } float getEmitRate() const { return _emitRate; } static const float DEFAULT_EMIT_SPEED; - static const float MINIMUM_EMIT_SPEED; - static const float MAXIMUM_EMIT_SPEED; void setEmitSpeed(float emitSpeed); float getEmitSpeed() const { return _emitSpeed; } @@ -153,69 +141,53 @@ public: const glm::quat& getEmitOrientation() const { return _emitOrientation; } static const glm::vec3 DEFAULT_EMIT_DIMENSIONS; - static const float MINIMUM_EMIT_DIMENSION; - static const float MAXIMUM_EMIT_DIMENSION; void setEmitDimensions(const glm::vec3& emitDimensions); const glm::vec3& getEmitDimensions() const { return _emitDimensions; } static const float DEFAULT_EMIT_RADIUS_START; - static const float MINIMUM_EMIT_RADIUS_START; - static const float MAXIMUM_EMIT_RADIUS_START; - void setEmitRadiusStart(float emitRadiusStart); + void setEmitRadiusStart(float emitRadiusStart) { _emitRadiusStart = emitRadiusStart; } float getEmitRadiusStart() const { return _emitRadiusStart; } - static const float MINIMUM_POLAR; - static const float MAXIMUM_POLAR; - static const float DEFAULT_POLAR_START; - void setPolarStart(float polarStart) { _polarStart = glm::clamp(polarStart, MINIMUM_POLAR, MAXIMUM_POLAR); } + void setPolarStart(float polarStart) { _polarStart = polarStart; } float getPolarStart() const { return _polarStart; } static const float DEFAULT_POLAR_FINISH; - void setPolarFinish(float polarFinish) { _polarFinish = glm::clamp(polarFinish, MINIMUM_POLAR, MAXIMUM_POLAR); } + void setPolarFinish(float polarFinish) { _polarFinish = polarFinish; } float getPolarFinish() const { return _polarFinish; } - static const float MINIMUM_AZIMUTH; - static const float MAXIMUM_AZIMUTH; - static const float DEFAULT_AZIMUTH_START; - void setAzimuthStart(float azimuthStart) { _azimuthStart = glm::clamp(azimuthStart, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH); } + void setAzimuthStart(float azimuthStart) { _azimuthStart = azimuthStart; } float getAzimuthStart() const { return _azimuthStart; } static const float DEFAULT_AZIMUTH_FINISH; - void setAzimuthFinish(float azimuthFinish) { _azimuthFinish = glm::clamp(azimuthFinish, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH); } + void setAzimuthFinish(float azimuthFinish) { _azimuthFinish = azimuthFinish; } float getAzimuthFinish() const { return _azimuthFinish; } static const glm::vec3 DEFAULT_EMIT_ACCELERATION; - static const float MINIMUM_EMIT_ACCELERATION; - static const float MAXIMUM_EMIT_ACCELERATION; void setEmitAcceleration(const glm::vec3& emitAcceleration); const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; } static const glm::vec3 DEFAULT_ACCELERATION_SPREAD; - static const float MINIMUM_ACCELERATION_SPREAD; - static const float MAXIMUM_ACCELERATION_SPREAD; void setAccelerationSpread(const glm::vec3& accelerationSpread); const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; } static const float DEFAULT_PARTICLE_RADIUS; - static const float MINIMUM_PARTICLE_RADIUS; - static const float MAXIMUM_PARTICLE_RADIUS; - void setParticleRadius(float particleRadius); + void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } float getParticleRadius() const { return _particleRadius; } static const float DEFAULT_RADIUS_START; bool _isRadiusStartInitialized = false; - void setRadiusStart(float radiusStart); + void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; } float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; } static const float DEFAULT_RADIUS_FINISH; bool _isRadiusFinishInitialized = false; - void setRadiusFinish(float radiusFinish); + void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; } float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; } static const float DEFAULT_RADIUS_SPREAD; - void setRadiusSpread(float radiusSpread); + void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; } float getRadiusSpread() const { return _radiusSpread; } void computeAndUpdateDimensions(); From 8cd549c958186b568f71b18d0bd9ad5f22268d61 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 5 Oct 2015 14:02:24 -0700 Subject: [PATCH 38/56] adjust chair and plant starting positions --- unpublishedScripts/masterReset.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index d6759e2b48..1bca00a6f3 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -71,13 +71,13 @@ function createAllToys() { createCombinedArmChair({ x: 549.29, - y: 495.05, + y: 494.9, z: 508.22 }); createPottedPlant({ x: 554.26, - y: 495.23, + y: 495.2, z: 504.53 }); @@ -98,7 +98,7 @@ function createAllToys() { function deleteAllToys() { var entities = Entities.findEntities(MyAvatar.position, 100); - entities.forEach(function (entity) { + entities.forEach(function(entity) { //params: customKey, id, defaultValue var shouldReset = getEntityCustomData(resetKey, entity, {}).resetMe; if (shouldReset === true) { @@ -831,4 +831,4 @@ function cleanup() { if (shouldDeleteOnEndScript) { Script.scriptEnding.connect(cleanup); -} +} \ No newline at end of file From 7f8411d947a714e11d7a3aceb04f8cb2b58d5fc8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 5 Oct 2015 14:15:38 -0700 Subject: [PATCH 39/56] reference count grabs on an entity --- examples/controllers/handControllerGrab.js | 66 +++++++++++----------- examples/grab.js | 49 ++++++++++++---- 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 90b85b15da..cdcb15d9dc 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -79,10 +79,8 @@ var STATE_NEAR_GRABBING_NON_COLLIDING = 6; var STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING = 7; var STATE_RELEASE = 8; -var GRAB_USER_DATA_KEY = "grabKey"; -var GRABBABLE_DATA_KEY = "grabbableKey"; -var GRAVITY_USER_DATA_KEY = "preGrabGravity"; -var IGNORE_FOR_COLLISIONS_USER_DATA_KEY = "preGrabIgnoreForCollisions"; +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js function getTag() { return "grab-" + MyAvatar.sessionUUID; @@ -314,7 +312,8 @@ function MyController(hand, triggerAction) { var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", + "gravity", "ignoreForCollisions"]); // add the action and initialize some variables this.currentObjectPosition = grabbedProperties.position; @@ -338,7 +337,7 @@ function MyController(hand, triggerAction) { if (this.actionID !== null) { this.setState(STATE_CONTINUE_DISTANCE_HOLDING); - this.activateEntity(this.grabbedEntity); + this.activateEntity(this.grabbedEntity, grabbedProperties); if (this.hand === RIGHT_HAND) { Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); } else { @@ -441,10 +440,9 @@ function MyController(hand, triggerAction) { this.lineOff(); - this.activateEntity(this.grabbedEntity); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", "gravity", "ignoreForCollisions"]); + this.activateEntity(this.grabbedEntity, grabbedProperties); var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); @@ -456,14 +454,6 @@ function MyController(hand, triggerAction) { var offset = Vec3.subtract(currentObjectPosition, handPosition); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); - // zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done - this.saveGravity = getEntityCustomData(GRAVITY_USER_DATA_KEY, this.grabbedEntity, grabbedProperties.gravity); - setEntityCustomData(GRAVITY_USER_DATA_KEY, this.grabbedEntity, this.saveGravity); - this.saveIgnoreForCollisions = getEntityCustomData(IGNORE_FOR_COLLISIONS_USER_DATA_KEY, this.grabbedEntity, - grabbedProperties.ignoreForCollisions); - setEntityCustomData(IGNORE_FOR_COLLISIONS_USER_DATA_KEY, this.grabbedEntity, this.saveIgnoreForCollisions); - Entities.editEntity(this.grabbedEntity, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true}); - this.actionID = NULL_ACTION_ID; this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, { hand: this.hand === RIGHT_HAND ? "right" : "left", @@ -492,12 +482,7 @@ function MyController(hand, triggerAction) { this.continueNearGrabbing = function() { if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.editEntity(this.grabbedEntity, - {gravity: this.saveGravity, ignoreForCollisions: this.saveIgnoreForCollisions}); - setEntityCustomData(IGNORE_FOR_COLLISIONS_USER_DATA_KEY, this.grabbedEntity, null); - setEntityCustomData(GRAVITY_USER_DATA_KEY, this.grabbedEntity, null); return; } @@ -656,20 +641,35 @@ function MyController(hand, triggerAction) { this.release(); }; - this.activateEntity = function() { - var data = { - activated: true, - avatarId: MyAvatar.sessionUUID - }; - setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); + this.activateEntity = function(entityID, grabbedProperties) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true}); + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); }; - this.deactivateEntity = function() { - var data = { - activated: false, - avatarId: null - }; - setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); }; } diff --git a/examples/grab.js b/examples/grab.js index 1e0adf9f1b..1c49775a49 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -26,7 +26,8 @@ var IDENTITY_QUAT = { z: 0, w: 0 }; -var GRABBABLE_DATA_KEY = "grabbableKey"; +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with handControllerGrab.js var defaultGrabbableData = { grabbable: true @@ -247,7 +248,6 @@ Grabber = function() { this.currentPosition = ZERO_VEC3; this.planeNormal = ZERO_VEC3; - this.originalGravity = ZERO_VEC3; // maxDistance is a function of the size of the object. this.maxDistance; @@ -346,14 +346,11 @@ Grabber.prototype.pressEvent = function(event) { return; } - Entities.editEntity(clickedEntity, { - gravity: ZERO_VEC3 - }); + this.activateEntity(clickedEntity, entityProperties); this.isGrabbing = true; this.entityID = clickedEntity; this.currentPosition = entityProperties.position; - this.originalGravity = entityProperties.gravity; this.targetPosition = { x: this.startPosition.x, y: this.startPosition.y, @@ -379,12 +376,7 @@ Grabber.prototype.pressEvent = function(event) { Grabber.prototype.releaseEvent = function() { if (this.isGrabbing) { - if (Vec3.length(this.originalGravity) != 0) { - Entities.editEntity(this.entityID, { - gravity: this.originalGravity - }); - } - + this.deactivateEntity(this.entityID); this.isGrabbing = false Entities.deleteAction(this.entityID, this.actionID); this.actionID = null; @@ -503,6 +495,39 @@ Grabber.prototype.keyPressEvent = function(event) { this.computeNewGrabPlane(); } +Grabber.prototype.activateEntity = function(entityID, grabbedProperties) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true}); + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); +}; + +Grabber.prototype.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); +}; + + + var grabber = new Grabber(); function pressEvent(event) { From 99be44f92d77dfc18c4d1a7678bc2157c39534df Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 5 Oct 2015 14:58:42 -0700 Subject: [PATCH 40/56] smooth out vibrating appearance for kinematic hold --- interface/src/avatar/AvatarActionKinematicHold.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index 21f2989299..84310cd35f 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -87,15 +87,19 @@ void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { return; } + if (_previousSet) { + glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep; + rigidBody->setLinearVelocity(glmToBullet(positionalVelocity)); + + // back up along velocity a bit in order to smooth out a "vibrating" appearance + _positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f; + } + btTransform worldTrans = rigidBody->getWorldTransform(); worldTrans.setOrigin(glmToBullet(_positionalTarget)); worldTrans.setRotation(glmToBullet(_rotationalTarget)); rigidBody->setWorldTransform(worldTrans); - if (_previousSet) { - glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep; - rigidBody->setLinearVelocity(glmToBullet(positionalVelocity)); - } _previousPositionalTarget = _positionalTarget; _previousRotationalTarget = _rotationalTarget; _previousSet = true; From 598aab884eef819467c71a65635732e06ca4a72b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 5 Oct 2015 14:59:28 -0700 Subject: [PATCH 41/56] Make log more readable --- libraries/shared/src/LogHandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index d1f23531cb..22ea12c1b3 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -120,11 +120,11 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont } // log prefix is in the following format - // [DEBUG] [TIMESTAMP] [PID] [TARGET] logged string + // [TIMESTAMP] [DEBUG] [PID] [TARGET] logged string - QString prefixString = QString("[%1]").arg(stringForLogType(type)); + QString prefixString = QString("[%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT)); - prefixString.append(QString(" [%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT))); + prefixString.append(QString(" [%1]").arg(stringForLogType(type))); if (_shouldOutputPID) { prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid())); From 9bc95a0fc120f142b821afe33777dae978a5fba3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:17:10 -0700 Subject: [PATCH 42/56] fix override warnings in assignment-client --- assignment-client/src/entities/EntityServer.h | 26 +++++++++---------- libraries/octree/src/OctreeHeadlessViewer.h | 6 ++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 114e0e1726..065834cbc2 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -26,28 +26,28 @@ public: ~EntityServer(); // Subclasses must implement these methods - virtual OctreeQueryNode* createOctreeQueryNode(); - virtual char getMyNodeType() const { return NodeType::EntityServer; } - virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } - virtual const char* getMyServerName() const { return MODEL_SERVER_NAME; } - virtual const char* getMyLoggingServerTargetName() const { return MODEL_SERVER_LOGGING_TARGET_NAME; } - virtual const char* getMyDefaultPersistFilename() const { return LOCAL_MODELS_PERSIST_FILE; } - virtual PacketType getMyEditNackType() const { return PacketType::EntityEditNack; } - virtual QString getMyDomainSettingsKey() const { return QString("entity_server_settings"); } + virtual OctreeQueryNode* createOctreeQueryNode() override ; + virtual char getMyNodeType() const override { return NodeType::EntityServer; } + virtual PacketType getMyQueryMessageType() const override { return PacketType::EntityQuery; } + virtual const char* getMyServerName() const override { return MODEL_SERVER_NAME; } + virtual const char* getMyLoggingServerTargetName() const override { return MODEL_SERVER_LOGGING_TARGET_NAME; } + virtual const char* getMyDefaultPersistFilename() const override { return LOCAL_MODELS_PERSIST_FILE; } + virtual PacketType getMyEditNackType() const override { return PacketType::EntityEditNack; } + virtual QString getMyDomainSettingsKey() const override { return QString("entity_server_settings"); } // subclass may implement these method - virtual void beforeRun(); - virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node); - virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent); + virtual void beforeRun() override; + virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node) override; + virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) override; - virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode); + virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override; virtual bool readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; public slots: void pruneDeletedEntities(); protected: - virtual OctreePointer createTree(); + virtual OctreePointer createTree() override; private slots: void handleEntityPacket(QSharedPointer packet, SharedNodePointer senderNode); diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index 5a17f48a19..605db15cd2 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -30,9 +30,9 @@ class OctreeHeadlessViewer : public OctreeRenderer { public: OctreeHeadlessViewer(); virtual ~OctreeHeadlessViewer() {}; - virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { /* swallow these */ } + virtual void renderElement(OctreeElementPointer element, RenderArgs* args) override { /* swallow these */ } - virtual void init(); + virtual void init() override ; virtual void render(RenderArgs* renderArgs) override { /* swallow these */ } void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } @@ -58,7 +58,7 @@ public slots: // getters for LOD and PPS float getVoxelSizeScale() const { return _voxelSizeScale; } - int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } + int getBoundaryLevelAdjust() const override { return _boundaryLevelAdjust; } int getMaxPacketsPerSecond() const { return _maxPacketsPerSecond; } unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); } From e835b5ccf397729f0c120700c7d50121a76c723e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:30:26 -0700 Subject: [PATCH 43/56] remove old gnutls code from domain-server --- domain-server/src/DomainServer.cpp | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 614b0a1528..48bb9bed62 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -133,33 +133,14 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { QString keyPath = _settingsManager.getSettingsMap().value(X509_PRIVATE_KEY_OPTION).toString(); if (!certPath.isEmpty() && !keyPath.isEmpty()) { - // the user wants to use DTLS to encrypt communication with nodes + // the user wants to use the following cert and key for HTTPS + // this is used for Oauth callbacks when authorizing users against a data server // let's make sure we can load the key and certificate -// _x509Credentials = new gnutls_certificate_credentials_t; -// gnutls_certificate_allocate_credentials(_x509Credentials); QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV); - qDebug() << "Reading certificate file at" << certPath << "for DTLS."; - qDebug() << "Reading key file at" << keyPath << "for DTLS."; - -// int gnutlsReturn = gnutls_certificate_set_x509_key_file2(*_x509Credentials, -// certPath.toLocal8Bit().constData(), -// keyPath.toLocal8Bit().constData(), -// GNUTLS_X509_FMT_PEM, -// keyPassphraseString.toLocal8Bit().constData(), -// 0); -// -// if (gnutlsReturn < 0) { -// qDebug() << "Unable to load certificate or key file." << "Error" << gnutlsReturn << "- domain-server will now quit."; -// QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); -// return false; -// } - -// qDebug() << "Successfully read certificate and private key."; - - // we need to also pass this certificate and private key to the HTTPS manager - // this is used for Oauth callbacks when authorizing users against a data server + qDebug() << "Reading certificate file at" << certPath << "for HTTPS."; + qDebug() << "Reading key file at" << keyPath << "for HTTPS."; QFile certFile(certPath); certFile.open(QIODevice::ReadOnly); From 1e01d6bd8f0f16e0015278c9dec3a0366a6f808b Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Mon, 5 Oct 2015 15:30:53 -0700 Subject: [PATCH 44/56] Add the ability to switch between mono and stereo in HMD Add the ability to switch between mono and stereo in HMD --- examples/utilities/tools/MonoHMD.js | 68 +++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 examples/utilities/tools/MonoHMD.js diff --git a/examples/utilities/tools/MonoHMD.js b/examples/utilities/tools/MonoHMD.js new file mode 100644 index 0000000000..5ab0ea4d64 --- /dev/null +++ b/examples/utilities/tools/MonoHMD.js @@ -0,0 +1,68 @@ +// +// MonoHMD.js +// +// Created by Chris Collins on 10/5/15 +// Copyright 2015 High Fidelity, Inc. +// +// This script allows you to switch between mono and stereo mode within the HMD. +// It will add adition menu to Tools called "IPD". +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + + + +function setupipdMenu() { + if (!Menu.menuExists("Tools > IPD")) { + Menu.addMenu("Tools > IPD"); + } + if (!Menu.menuItemExists("Tools > IPD", "Stereo")) { + Menu.addMenuItem({ + menuName: "Tools > IPD", + menuItemName: "Stereo", + isCheckable: true, + isChecked: true + }); + } + if (!Menu.menuItemExists("Tools > IPD", "Mono")) { + Menu.addMenuItem({ + menuName: "Tools > IPD", + menuItemName: "Mono", + isCheckable: true, + isChecked: false + }); + } + +} + + +function menuItemEvent(menuItem) { + if (menuItem == "Stereo") { + Menu.setIsOptionChecked("Mono", false); + HMD.setIPDScale(1.0); + + } + if (menuItem == "Mono") { + Menu.setIsOptionChecked("Stereo", false); + HMD.setIPDScale(0.0); + } + +} + + + +function scriptEnding() { + + Menu.removeMenuItem("Tools > IPD", "Stereo"); + Menu.removeMenuItem("Tools > IPD", "Mono"); + Menu.removeMenu("Tools > IPD"); + //reset the HMD to stereo mode + HMD.setIPDScale(1.0); + +} + + +setupipdMenu(); +Menu.menuItemEvent.connect(menuItemEvent); +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From c0a881ec52321f8a339d8e4951dd865ba67d19da Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Mon, 5 Oct 2015 15:37:04 -0700 Subject: [PATCH 45/56] added the correct call added the correct call --- examples/utilities/tools/MonoHMD.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/MonoHMD.js b/examples/utilities/tools/MonoHMD.js index 5ab0ea4d64..4565ebd7bf 100644 --- a/examples/utilities/tools/MonoHMD.js +++ b/examples/utilities/tools/MonoHMD.js @@ -40,12 +40,12 @@ function setupipdMenu() { function menuItemEvent(menuItem) { if (menuItem == "Stereo") { Menu.setIsOptionChecked("Mono", false); - HMD.setIPDScale(1.0); + HMD.ipdScale = 1.0; } if (menuItem == "Mono") { Menu.setIsOptionChecked("Stereo", false); - HMD.setIPDScale(0.0); + HMD.ipdScale = 0.0; } } From 3ddfcc10c2dcf591038f8d8af9d7dadaeac89deb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:50:35 -0700 Subject: [PATCH 46/56] override additions to input-plugins --- libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h | 2 +- libraries/input-plugins/src/input-plugins/SDL2Manager.h | 2 +- libraries/input-plugins/src/input-plugins/SixenseManager.h | 2 +- .../input-plugins/src/input-plugins/ViveControllerManager.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index 70e2ee5d34..6f703bc6f9 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -59,7 +59,7 @@ public: // Plugin functions virtual bool isSupported() const override { return true; } virtual bool isJointController() const override { return false; } - const QString& getName() const { return NAME; } + const QString& getName() const override { return NAME; } virtual void activate() override {}; virtual void deactivate() override {}; diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h index f017e2cc65..52d39597ef 100644 --- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h +++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h @@ -30,7 +30,7 @@ public: // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return false; } - const QString& getName() const { return NAME; } + const QString& getName() const override { return NAME; } virtual void init() override; virtual void deinit() override; diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h index 22340cfc95..5e3815cd20 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.h +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h @@ -63,7 +63,7 @@ public: // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } - const QString& getName() const { return NAME; } + const QString& getName() const override { return NAME; } virtual void activate() override; virtual void deactivate() override; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index 98f32b9f35..5cae8daaf4 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -53,7 +53,7 @@ public: // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } - const QString& getName() const { return NAME; } + const QString& getName() const override { return NAME; } virtual void activate() override; virtual void deactivate() override; From a2c9d7a4b2502837918512529896a7b28b2dad2c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:52:47 -0700 Subject: [PATCH 47/56] add overrides for Avatar classes in Interface --- interface/src/avatar/MyAvatar.h | 32 ++++++++++++++-------------- interface/src/avatar/SkeletonModel.h | 6 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 96c9f37c39..5d87737dd7 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -139,19 +139,19 @@ public: void updateLookAtTargetAvatar(); void clearLookAtTargetAvatar(); - virtual void setJointRotations(QVector jointRotations); - virtual void setJointTranslations(QVector jointTranslations); - virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation); - virtual void setJointRotation(int index, const glm::quat& rotation); - virtual void setJointTranslation(int index, const glm::vec3& translation); - virtual void clearJointData(int index); - virtual void clearJointsData(); + virtual void setJointRotations(QVector jointRotations) override; + virtual void setJointTranslations(QVector jointTranslations) override; + virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) override; + virtual void setJointRotation(int index, const glm::quat& rotation) override; + virtual void setJointTranslation(int index, const glm::vec3& translation) override; + virtual void clearJointData(int index) override; + virtual void clearJointsData() override; Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } Q_INVOKABLE const QString& getFullAvatarModelName() const { return _fullAvatarModelName; } - virtual void setAttachmentData(const QVector& attachmentData); + virtual void setAttachmentData(const QVector& attachmentData) override; DynamicCharacterController* getCharacterController() { return &_characterController; } @@ -218,7 +218,7 @@ public slots: void saveRecording(QString filename); void loadLastRecording(); - virtual void rebuildSkeletonBody(); + virtual void rebuildSkeletonBody() override; bool getEnableRigAnimations() const { return _rig->getEnableRig(); } void setEnableRigAnimations(bool isEnabled); @@ -243,7 +243,7 @@ private: glm::vec3 getWorldBodyPosition() const; glm::quat getWorldBodyOrientation() const; - QByteArray toByteArray(bool cullSmallChanges, bool sendAll); + QByteArray toByteArray(bool cullSmallChanges, bool sendAll) override; void simulate(float deltaTime); void updateFromTrackers(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; @@ -252,9 +252,9 @@ private: void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } bool getShouldRenderLocally() const { return _shouldRender; } bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; - bool isMyAvatar() const { return true; } - virtual int parseDataFromBuffer(const QByteArray& buffer); - virtual glm::vec3 getSkeletonPosition() const; + bool isMyAvatar() const override { return true; } + virtual int parseDataFromBuffer(const QByteArray& buffer) override; + virtual glm::vec3 getSkeletonPosition() const override; glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; } float getScriptedMotorTimescale() const { return _scriptedMotorTimescale; } @@ -264,7 +264,7 @@ private: void setScriptedMotorFrame(QString frame); virtual void attach(const QString& modelURL, const QString& jointName = QString(), const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, - bool allowDuplicates = false, bool useSaved = true); + bool allowDuplicates = false, bool useSaved = true) override; void renderLaserPointers(gpu::Batch& batch); const RecorderPointer getRecorder() const { return _recorder; } @@ -273,8 +273,8 @@ private: bool cameraInsideHead() const; // These are made private for MyAvatar so that you will use the "use" methods instead - virtual void setFaceModelURL(const QUrl& faceModelURL); - virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); + virtual void setFaceModelURL(const QUrl& faceModelURL) override; + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index e2c3ab8f83..d655d6e01f 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -27,10 +27,10 @@ public: SkeletonModel(Avatar* owningAvatar, QObject* parent = nullptr, RigPointer rig = nullptr); ~SkeletonModel(); - virtual void initJointStates(QVector states); + virtual void initJointStates(QVector states) override; - virtual void simulate(float deltaTime, bool fullUpdate = true); - virtual void updateRig(float deltaTime, glm::mat4 parentTransform); + virtual void simulate(float deltaTime, bool fullUpdate = true) override; + virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; void updateAttitude(); void renderIKConstraints(gpu::Batch& batch); From 25a1f2dd11a855c544f6c2d8b79e21a9c9d2d9c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:53:37 -0700 Subject: [PATCH 48/56] add override to suppress warning for PluginContainerProxy --- interface/src/PluginContainerProxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index e01cabc3b8..16e9b951fe 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -16,7 +16,7 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override; virtual bool isOptionChecked(const QString& name) override; - virtual void setIsOptionChecked(const QString& path, bool checked); + virtual void setIsOptionChecked(const QString& path, bool checked) override; virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override; virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override; virtual void showDisplayPluginsTools() override; From 7bd98354d819219aa6557337a0ca6a2cd3891e9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:53:52 -0700 Subject: [PATCH 49/56] add override to supress warnings in ui-test --- tests/ui/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 6611e8f343..3879d0b029 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -260,7 +260,7 @@ protected: } - void keyPressEvent(QKeyEvent* event) { + void keyPressEvent(QKeyEvent* event) override { _altPressed = Qt::Key_Alt == event->key(); switch (event->key()) { case Qt::Key_B: @@ -292,13 +292,13 @@ protected: QWindow::keyPressEvent(event); } QQmlContext* menuContext{ nullptr }; - void keyReleaseEvent(QKeyEvent *event) { + void keyReleaseEvent(QKeyEvent *event) override { if (_altPressed && Qt::Key_Alt == event->key()) { VrMenu::toggle(); } } - void moveEvent(QMoveEvent* event) { + void moveEvent(QMoveEvent* event) override { static qreal oldPixelRatio = 0.0; if (devicePixelRatio() != oldPixelRatio) { oldPixelRatio = devicePixelRatio(); From 5989cad054410eb64d0fc23d671245b6fc41597c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Oct 2015 15:55:05 -0700 Subject: [PATCH 50/56] add override qualifier to suppress warnings in entities-renderer --- .../src/RenderableParticleEffectEntityItem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 9581c43ca5..5d69d19026 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -25,8 +25,8 @@ public: void updateRenderItem(); - virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges); - virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges); + virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; + virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; protected: render::ItemID _renderItemId; From 91f5a6fec6b79a43e2a1013a04b0e07dc9531057 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Oct 2015 08:08:33 -0700 Subject: [PATCH 51/56] make setting of rigid-body velocity controlled by an action argument --- .../src/avatar/AvatarActionKinematicHold.cpp | 23 +++++++++++++------ .../src/avatar/AvatarActionKinematicHold.h | 2 ++ .../entities/src/EntityActionInterface.cpp | 22 ++++++++++++++++++ .../entities/src/EntityActionInterface.h | 2 ++ 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index 84310cd35f..781d895a32 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -81,18 +81,19 @@ void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { void* physicsInfo = ownerEntity->getPhysicsInfo(); if (physicsInfo) { ObjectMotionState* motionState = static_cast(physicsInfo); - btRigidBody* rigidBody = motionState->getRigidBody(); + btRigidBody* rigidBody = motionState ? motionState->getRigidBody() : nullptr; if (!rigidBody) { qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody"; return; } - if (_previousSet) { - glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep; - rigidBody->setLinearVelocity(glmToBullet(positionalVelocity)); - - // back up along velocity a bit in order to smooth out a "vibrating" appearance - _positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f; + if (_setVelocity) { + if (_previousSet) { + glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep; + rigidBody->setLinearVelocity(glmToBullet(positionalVelocity)); + // back up along velocity a bit in order to smooth out a "vibrating" appearance + _positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f; + } } btTransform worldTrans = rigidBody->getWorldTransform(); @@ -140,6 +141,13 @@ bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) { hand = _hand; } + ok = true; + int setVelocity = + EntityActionInterface::extractIntegerArgument("kinematic-hold", arguments, "setVelocity", ok, false); + if (!ok) { + setVelocity = false; + } + if (relativePosition != _relativePosition || relativeRotation != _relativeRotation || hand != _hand) { @@ -147,6 +155,7 @@ bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) { _relativePosition = relativePosition; _relativeRotation = relativeRotation; _hand = hand; + _setVelocity = setVelocity; _mine = true; _active = true; diff --git a/interface/src/avatar/AvatarActionKinematicHold.h b/interface/src/avatar/AvatarActionKinematicHold.h index 95e9605c2b..b4fceab1e7 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.h +++ b/interface/src/avatar/AvatarActionKinematicHold.h @@ -40,6 +40,8 @@ private: bool _previousSet = false; glm::vec3 _previousPositionalTarget; glm::quat _previousRotationalTarget; + + bool _setVelocity = false; }; #endif // hifi_AvatarActionKinematicHold_h diff --git a/libraries/entities/src/EntityActionInterface.cpp b/libraries/entities/src/EntityActionInterface.cpp index 25f61fcf25..c34f072601 100644 --- a/libraries/entities/src/EntityActionInterface.cpp +++ b/libraries/entities/src/EntityActionInterface.cpp @@ -249,6 +249,28 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa return v; } +int EntityActionInterface::extractIntegerArgument(QString objectName, QVariantMap arguments, + QString argumentName, bool& ok, bool required) { + if (!arguments.contains(argumentName)) { + if (required) { + qDebug() << objectName << "requires argument:" << argumentName; + } + ok = false; + return 0.0f; + } + + QVariant vV = arguments[argumentName]; + bool vOk = true; + int v = vV.toInt(&vOk); + + if (!vOk || v != v) { + ok = false; + return 0; + } + + return v; +} + QString EntityActionInterface::extractStringArgument(QString objectName, QVariantMap arguments, QString argumentName, bool& ok, bool required) { if (!arguments.contains(argumentName)) { diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index b5d277587c..57f605c3e3 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -70,6 +70,8 @@ protected: QString argumentName, bool& ok, bool required = true); static float extractFloatArgument(QString objectName, QVariantMap arguments, QString argumentName, bool& ok, bool required = true); + static int extractIntegerArgument(QString objectName, QVariantMap arguments, + QString argumentName, bool& ok, bool required = true); static QString extractStringArgument(QString objectName, QVariantMap arguments, QString argumentName, bool& ok, bool required = true); From c3142ab90b2079615b4a34bb67eb4c40f732461d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Oct 2015 09:20:07 -0700 Subject: [PATCH 52/56] include setVelocity in returned arguments --- interface/src/avatar/AvatarActionKinematicHold.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index 781d895a32..521230adc6 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -176,6 +176,7 @@ QVariantMap AvatarActionKinematicHold::getArguments() { arguments["relativePosition"] = glmToQMap(_relativePosition); arguments["relativeRotation"] = glmToQMap(_relativeRotation); + arguments["setVelocity"] = glmToQMap((int)_setVelocity); arguments["hand"] = _hand; }); return arguments; From 18b5b994b4e41e8f8cfa1b43173320000560facb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Oct 2015 09:23:38 -0700 Subject: [PATCH 53/56] include setVelocity in returned arguments --- interface/src/avatar/AvatarActionKinematicHold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index 521230adc6..b792058846 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -176,7 +176,7 @@ QVariantMap AvatarActionKinematicHold::getArguments() { arguments["relativePosition"] = glmToQMap(_relativePosition); arguments["relativeRotation"] = glmToQMap(_relativeRotation); - arguments["setVelocity"] = glmToQMap((int)_setVelocity); + arguments["setVelocity"] = glmToQMap((quint8)_setVelocity); arguments["hand"] = _hand; }); return arguments; From 5abaf38efd6acb314dd29b78a953ab26cfaf7be7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Oct 2015 09:24:18 -0700 Subject: [PATCH 54/56] include setVelocity in returned arguments --- interface/src/avatar/AvatarActionKinematicHold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index b792058846..9831fca47c 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -176,7 +176,7 @@ QVariantMap AvatarActionKinematicHold::getArguments() { arguments["relativePosition"] = glmToQMap(_relativePosition); arguments["relativeRotation"] = glmToQMap(_relativeRotation); - arguments["setVelocity"] = glmToQMap((quint8)_setVelocity); + arguments["setVelocity"] = _setVelocity; arguments["hand"] = _hand; }); return arguments; From 8caa7abca67d7a15856ecffec1cdbd52cd37ee21 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 6 Oct 2015 09:35:54 -0700 Subject: [PATCH 55/56] assert that deltaTimeStep is always greater than zero --- interface/src/avatar/AvatarActionKinematicHold.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/avatar/AvatarActionKinematicHold.cpp b/interface/src/avatar/AvatarActionKinematicHold.cpp index 9831fca47c..680363877f 100644 --- a/interface/src/avatar/AvatarActionKinematicHold.cpp +++ b/interface/src/avatar/AvatarActionKinematicHold.cpp @@ -46,9 +46,7 @@ void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) { return; } - if (deltaTimeStep <= 0.0f) { - return; - } + assert(deltaTimeStep > 0.0f); glm::quat rotation; glm::vec3 position; From 8090bc8e8d7d2b65963aa1ad17e5fb45e06c61a5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 6 Oct 2015 10:16:42 -0700 Subject: [PATCH 56/56] Revert "Enabling programmatic access to the IPD scale" --- examples/example/hmd/ipdScalingTest.js | 42 ------------ interface/src/Application.cpp | 47 ++++--------- interface/src/PluginContainerProxy.cpp | 7 -- interface/src/PluginContainerProxy.h | 3 - interface/src/avatar/MyAvatar.cpp | 8 +-- .../src/scripting/HMDScriptingInterface.cpp | 68 +++++++++---------- .../src/scripting/HMDScriptingInterface.h | 23 ++++--- .../AbstractHMDScriptingInterface.cpp | 52 -------------- .../AbstractHMDScriptingInterface.h | 39 ----------- .../src/display-plugins/DisplayPlugin.h | 17 ++--- .../oculus/OculusBaseDisplayPlugin.cpp | 16 ++--- .../oculus/OculusBaseDisplayPlugin.h | 11 ++- .../display-plugins/oculus/OculusHelpers.h | 8 --- .../oculus/OculusLegacyDisplayPlugin.cpp | 4 +- .../oculus/OculusLegacyDisplayPlugin.h | 2 +- .../openvr/OpenVrDisplayPlugin.cpp | 4 +- .../openvr/OpenVrDisplayPlugin.h | 2 +- .../stereo/StereoDisplayPlugin.cpp | 4 ++ .../stereo/StereoDisplayPlugin.h | 9 +-- .../plugins/src/plugins/PluginContainer.cpp | 10 --- .../plugins/src/plugins/PluginContainer.h | 4 -- 21 files changed, 90 insertions(+), 290 deletions(-) delete mode 100644 examples/example/hmd/ipdScalingTest.js delete mode 100644 libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp delete mode 100644 libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h diff --git a/examples/example/hmd/ipdScalingTest.js b/examples/example/hmd/ipdScalingTest.js deleted file mode 100644 index daa11170e4..0000000000 --- a/examples/example/hmd/ipdScalingTest.js +++ /dev/null @@ -1,42 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/10/04 -// Copyright 2013-2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -IPDScalingTest = function() { - // Switch every 5 seconds between normal IPD and 0 IPD (in seconds) - this.UPDATE_INTERVAL = 10.0; - this.lastUpdateInterval = 0; - this.scaled = false; - - var that = this; - Script.scriptEnding.connect(function() { - that.onCleanup(); - }); - - Script.update.connect(function(deltaTime) { - that.lastUpdateInterval += deltaTime; - if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) { - that.onUpdate(that.lastUpdateInterval); - that.lastUpdateInterval = 0; - } - }); -} - -IPDScalingTest.prototype.onCleanup = function() { - HMD.setIPDScale(1.0); -} - -IPDScalingTest.prototype.onUpdate = function(deltaTime) { - this.scaled = !this.scaled; - if (this.scaled) { - HMD.ipdScale = 0.0; - } else { - HMD.ipdScale = 1.0; - } -} - -new IPDScalingTest(); \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 025e448e29..b25f3aa6a5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -300,7 +300,6 @@ bool setupEssentials(int& argc, char** argv) { auto desktopScriptingInterface = DependencyManager::set(); auto entityScriptingInterface = DependencyManager::set(); auto windowScriptingInterface = DependencyManager::set(); - auto hmdScriptingInterface = DependencyManager::set(); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::set(); #endif @@ -1204,11 +1203,9 @@ void Application::paintGL() { // right eye. There are FIXMEs in the relevant plugins _myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection())); renderArgs._context->enableStereo(true); - mat4 eyeOffsets[2]; + mat4 eyeViews[2]; mat4 eyeProjections[2]; auto baseProjection = renderArgs._viewFrustum->getProjection(); - auto hmdInterface = DependencyManager::get(); - float IPDScale = hmdInterface->getIPDScale(); // FIXME we probably don't need to set the projection matrix every frame, // only when the display plugin changes (or in non-HMD modes when the user // changes the FOV manually, which right now I don't think they can. @@ -1217,24 +1214,14 @@ void Application::paintGL() { // applied to the avatar, so we need to get the difference between the head // pose applied to the avatar and the per eye pose, and use THAT as // the per-eye stereo matrix adjustment. - mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye); - // Grab the translation - vec3 eyeOffset = glm::vec3(eyeToHead[3]); - // Apply IPD scaling - mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); - eyeOffsets[eye] = eyeOffsetTransform; - - // Tell the plugin what pose we're using to render. In this case we're just using the - // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it - // for rotational timewarp. If we move to support positonal timewarp, we need to - // ensure this contains the full pose composed with the eye offsets. + mat4 eyePose = displayPlugin->getEyePose(eye); mat4 headPose = displayPlugin->getHeadPose(); - displayPlugin->setEyeRenderPose(eye, headPose); - + mat4 eyeView = glm::inverse(eyePose) * headPose; + eyeViews[eye] = eyeView; eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection); }); renderArgs._context->setStereoProjections(eyeProjections); - renderArgs._context->setStereoViews(eyeOffsets); + renderArgs._context->setStereoViews(eyeViews); } displaySide(&renderArgs, _myCamera); renderArgs._context->enableStereo(false); @@ -4143,7 +4130,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Paths", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("HMD", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("HMD", &HMDScriptingInterface::getInstance()); scriptEngine->registerFunction("HMD", "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0); scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0); @@ -4993,25 +4980,19 @@ mat4 Application::getEyeProjection(int eye) const { mat4 Application::getEyePose(int eye) const { if (isHMDMode()) { - auto hmdInterface = DependencyManager::get(); - float IPDScale = hmdInterface->getIPDScale(); - auto displayPlugin = getActiveDisplayPlugin(); - mat4 headPose = displayPlugin->getHeadPose(); - mat4 eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye); - { - vec3 eyeOffset = glm::vec3(eyeToHead[3]); - // Apply IPD scaling - mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); - eyeToHead[3] = vec4(eyeOffset, 1.0); - } - return eyeToHead * headPose; + return getActiveDisplayPlugin()->getEyePose((Eye)eye); } + return mat4(); } mat4 Application::getEyeOffset(int eye) const { - // FIXME invert? - return getActiveDisplayPlugin()->getEyeToHeadTransform((Eye)eye); + if (isHMDMode()) { + mat4 identity; + return getActiveDisplayPlugin()->getView((Eye)eye, identity); + } + + return mat4(); } mat4 Application::getHMDSensorPose() const { diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index d31231e11c..469e7f7c77 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -16,9 +16,6 @@ PluginContainerProxy::PluginContainerProxy() { Plugin::setContainer(this); } -PluginContainerProxy::~PluginContainerProxy() { -} - bool PluginContainerProxy::isForeground() { return qApp->_isForeground && !qApp->getWindow()->isMinimized(); } @@ -154,7 +151,3 @@ void PluginContainerProxy::showDisplayPluginsTools() { QGLWidget* PluginContainerProxy::getPrimarySurface() { return qApp->_glWidget; } - -const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const { - return qApp->getActiveDisplayPlugin(); -} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 79f8287b66..95865609c8 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -11,7 +11,6 @@ class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); - virtual ~PluginContainerProxy(); virtual void addMenu(const QString& menuName) override; virtual void removeMenu(const QString& menuName) override; virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; @@ -24,8 +23,6 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual void requestReset() override; virtual QGLWidget* getPrimarySurface() override; virtual bool isForeground() override; - virtual const DisplayPlugin* getActiveDisplayPlugin() const override; - QRect _savedGeometry{ 10, 120, 800, 600 }; friend class Application; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 71698fa4ea..9654305d70 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1341,13 +1341,11 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (qApp->isHMDMode()) { glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); - glm::mat4 headPose = Application::getInstance()->getActiveDisplayPlugin()->getHeadPose(); - glm::mat4 leftEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left); - leftEyePose = leftEyePose * headPose; + glm::mat4 leftEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyePose(Eye::Left); glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]); - glm::mat4 rightEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right); - rightEyePose = rightEyePose * headPose; + glm::mat4 rightEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyePose(Eye::Right); glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]); + glm::mat4 headPose = Application::getInstance()->getActiveDisplayPlugin()->getHeadPose(); glm::vec3 headPosition = glm::vec3(headPose[3]); getHead()->renderLookAts(renderArgs, diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index f6bf7f8b3c..68ac511eaf 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -10,46 +10,12 @@ // #include "HMDScriptingInterface.h" - -#include - #include "display-plugins/DisplayPlugin.h" #include -#include "Application.h" -HMDScriptingInterface::HMDScriptingInterface() { -} - -QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { - glm::vec3 hudIntersection; - auto instance = DependencyManager::get(); - if (instance->getHUDLookAtPosition3D(hudIntersection)) { - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition(); - glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); - glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); - glm::vec3 eulers = ::safeEulerAngles(rotation); - return qScriptValueFromValue(engine, Application::getInstance()->getApplicationCompositor() - .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); - } - return QScriptValue::NullValue; -} - -QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) { - glm::vec3 result; - auto instance = DependencyManager::get(); - if (instance->getHUDLookAtPosition3D(result)) { - return qScriptValueFromValue(engine, result); - } - return QScriptValue::NullValue; -} - -void HMDScriptingInterface::toggleMagnifier() { - qApp->getApplicationCompositor().toggleMagnifier(); -} - -bool HMDScriptingInterface::getMagnifier() const { - return Application::getInstance()->getApplicationCompositor().hasMagnifier(); +HMDScriptingInterface& HMDScriptingInterface::getInstance() { + static HMDScriptingInterface sharedInstance; + return sharedInstance; } bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { @@ -63,3 +29,31 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { return compositor.calculateRayUICollisionPoint(position, direction, result); } + +QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { + + glm::vec3 hudIntersection; + + if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(hudIntersection)) { + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition(); + glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); + glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); + glm::vec3 eulers = ::safeEulerAngles(rotation); + return qScriptValueFromValue(engine, Application::getInstance()->getApplicationCompositor() + .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); + } + return QScriptValue::NullValue; +} + +QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) { + glm::vec3 result; + if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(result)) { + return qScriptValueFromValue(engine, result); + } + return QScriptValue::NullValue; +} + +float HMDScriptingInterface::getIPD() const { + return Application::getInstance()->getActiveDisplayPlugin()->getIPD(); +} diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index c097cde5e3..82b444abaa 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -12,29 +12,32 @@ #ifndef hifi_HMDScriptingInterface_h #define hifi_HMDScriptingInterface_h -#include -class QScriptContext; -class QScriptEngine; - #include -#include -#include +#include "Application.h" -class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency { +class HMDScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(bool magnifier READ getMagnifier) + Q_PROPERTY(bool active READ isHMDMode) + Q_PROPERTY(float ipd READ getIPD) public: - HMDScriptingInterface(); + static HMDScriptingInterface& getInstance(); + static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine); static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); public slots: - void toggleMagnifier(); + void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); }; private: - bool getMagnifier() const; + HMDScriptingInterface() {}; + bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); }; + bool isHMDMode() const { return Application::getInstance()->isHMDMode(); } + float getIPD() const; + bool getHUDLookAtPosition3D(glm::vec3& result) const; + }; #endif // hifi_HMDScriptingInterface_h diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp deleted file mode 100644 index 9987ae345c..0000000000 --- a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/10/04 -// Copyright 2013-2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "AbstractHMDScriptingInterface.h" - -#include - -#include "DisplayPlugin.h" -#include -#include - -static Setting::Handle IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f); - -AbstractHMDScriptingInterface::AbstractHMDScriptingInterface() { - _IPDScale = IPD_SCALE_HANDLE.get(); -} - -float AbstractHMDScriptingInterface::getIPD() const { - return PluginContainer::getInstance().getActiveDisplayPlugin()->getIPD(); -} - -float AbstractHMDScriptingInterface::getEyeHeight() const { - // FIXME update the display plugin interface to expose per-plugin settings - return OVR_DEFAULT_EYE_HEIGHT; -} - -float AbstractHMDScriptingInterface::getPlayerHeight() const { - // FIXME update the display plugin interface to expose per-plugin settings - return OVR_DEFAULT_PLAYER_HEIGHT; -} - -float AbstractHMDScriptingInterface::getIPDScale() const { - return _IPDScale; -} - -void AbstractHMDScriptingInterface::setIPDScale(float IPDScale) { - IPDScale = glm::clamp(IPDScale, -1.0f, 3.0f); - if (IPDScale != _IPDScale) { - _IPDScale = IPDScale; - IPD_SCALE_HANDLE.set(IPDScale); - emit IPDScaleChanged(); - } -} - -bool AbstractHMDScriptingInterface::isHMDMode() const { - return PluginContainer::getInstance().getActiveDisplayPlugin()->isHmd(); -} diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h deleted file mode 100644 index 5df58ce677..0000000000 --- a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/10/04 -// Copyright 2013-2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_AbstractHMDScriptingInterface_h -#define hifi_AbstractHMDScriptingInterface_h - -#include - -class AbstractHMDScriptingInterface : public QObject { - Q_OBJECT - Q_PROPERTY(bool active READ isHMDMode) - Q_PROPERTY(float ipd READ getIPD) - Q_PROPERTY(float eyeHeight READ getEyeHeight) - Q_PROPERTY(float playerHeight READ getPlayerHeight) - Q_PROPERTY(float ipdScale READ getIPDScale WRITE setIPDScale NOTIFY IPDScaleChanged) - -public: - AbstractHMDScriptingInterface(); - float getIPD() const; - float getEyeHeight() const; - float getPlayerHeight() const; - float getIPDScale() const; - void setIPDScale(float ipdScale); - bool isHMDMode() const; - -signals: - void IPDScaleChanged(); - -private: - float _IPDScale{ 1.0 }; -}; - -#endif // hifi_AbstractHMDScriptingInterface_h diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h index b4ae6be97f..8b9d249bd4 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h @@ -46,8 +46,6 @@ void for_each_eye(F f, FF ff) { class QWindow; -#define AVERAGE_HUMAN_IPD 0.064f - class DisplayPlugin : public Plugin { Q_OBJECT public: @@ -109,22 +107,21 @@ public: return baseProjection; } + virtual glm::mat4 getView(Eye eye, const glm::mat4& baseView) const { + return glm::inverse(getEyePose(eye)) * baseView; + } + // HMD specific methods // TODO move these into another class? - virtual glm::mat4 getEyeToHeadTransform(Eye eye) const { - static const glm::mat4 transform; return transform; + virtual glm::mat4 getEyePose(Eye eye) const { + static const glm::mat4 pose; return pose; } virtual glm::mat4 getHeadPose() const { static const glm::mat4 pose; return pose; } - // Needed for timewarp style features - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) { - // NOOP - } - - virtual float getIPD() const { return AVERAGE_HUMAN_IPD; } + virtual float getIPD() const { return 0.0f; } virtual void abandonCalibration() {} virtual void resetSensors() {} diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp index 859a4a810a..f2a7b06510 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp @@ -19,6 +19,7 @@ void OculusBaseDisplayPlugin::preRender() { #if (OVR_MAJOR_VERSION >= 6) ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex); _trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds); + ovr_CalcEyePoses(_trackingState.HeadPose.ThePose, _eyeOffsets, _eyePoses); #endif } @@ -32,19 +33,14 @@ void OculusBaseDisplayPlugin::resetSensors() { #endif } -glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const { - return glm::translate(mat4(), toGlm(_eyeOffsets[eye])); +glm::mat4 OculusBaseDisplayPlugin::getEyePose(Eye eye) const { + return toGlm(_eyePoses[eye]); } glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const { return toGlm(_trackingState.HeadPose.ThePose); } -void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) { - _eyePoses[eye] = ovrPoseFromGlm(pose); -} - - bool OculusBaseDisplayPlugin::isSupported() const { #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { @@ -155,9 +151,9 @@ void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sce } float OculusBaseDisplayPlugin::getIPD() const { - float result = OVR_DEFAULT_IPD; + float result = 0.0f; #if (OVR_MAJOR_VERSION >= 6) - result = ovr_GetFloat(_hmd, OVR_KEY_IPD, result); + result = ovr_GetFloat(_hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD); #endif return result; -} +} \ No newline at end of file diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h index 6307f6bbf9..d879085b8f 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h @@ -29,9 +29,8 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override final; virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); } virtual void resetSensors() override final; - virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final; + virtual glm::mat4 getEyePose(Eye eye) const override final; virtual glm::mat4 getHeadPose() const override final; - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final; virtual float getIPD() const override final; protected: @@ -40,7 +39,6 @@ protected: protected: ovrPosef _eyePoses[2]; - ovrVector3f _eyeOffsets[2]; mat4 _eyeProjections[3]; mat4 _compositeEyeProjections[2]; @@ -52,12 +50,13 @@ protected: ovrHmd _hmd; float _ipd{ OVR_DEFAULT_IPD }; ovrEyeRenderDesc _eyeRenderDescs[2]; + ovrVector3f _eyeOffsets[2]; ovrFovPort _eyeFovs[2]; - ovrHmdDesc _hmdDesc; - ovrLayerEyeFov _sceneLayer; + ovrHmdDesc _hmdDesc; + ovrLayerEyeFov _sceneLayer; #endif #if (OVR_MAJOR_VERSION == 7) - ovrGraphicsLuid _luid; + ovrGraphicsLuid _luid; #endif }; diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h b/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h index 5a6999075b..df0a6c5228 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h @@ -79,11 +79,3 @@ inline ovrQuatf ovrFromGlm(const glm::quat & q) { return{ q.x, q.y, q.z, q.w }; } -inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) { - glm::vec3 translation = glm::vec3(m[3]) / m[3].w; - glm::quat orientation = glm::quat_cast(m); - ovrPosef result; - result.Orientation = ovrFromGlm(orientation); - result.Position = ovrFromGlm(translation); - return result; -} diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp index 1ad61513d6..ade34afcae 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp @@ -59,11 +59,11 @@ void OculusLegacyDisplayPlugin::resetSensors() { #endif } -glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const { +glm::mat4 OculusLegacyDisplayPlugin::getEyePose(Eye eye) const { #if (OVR_MAJOR_VERSION == 5) return toGlm(_eyePoses[eye]); #else - return WindowOpenGLDisplayPlugin::getEyeToHeadTransform(eye); + return WindowOpenGLDisplayPlugin::getEyePose(eye); #endif } diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h index 9e2e47f434..5bce032948 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h @@ -31,7 +31,7 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override; virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); } virtual void resetSensors() override; - virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; + virtual glm::mat4 getEyePose(Eye eye) const override; virtual glm::mat4 getHeadPose() const override; protected: diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index faf5a7b781..fab9cc5dd4 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -160,8 +160,8 @@ void OpenVrDisplayPlugin::resetSensors() { _sensorResetMat = glm::inverse(cancelOutRollAndPitch(_trackedDevicePoseMat4[0])); } -glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const { - return _eyesData[eye]._eyeOffset; +glm::mat4 OpenVrDisplayPlugin::getEyePose(Eye eye) const { + return getHeadPose() * _eyesData[eye]._eyeOffset; } glm::mat4 OpenVrDisplayPlugin::getHeadPose() const { diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h index 7849623552..afe024e72b 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h @@ -29,7 +29,7 @@ public: virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; virtual void resetSensors() override; - virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; + virtual glm::mat4 getEyePose(Eye eye) const override; virtual glm::mat4 getHeadPose() const override; protected: diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index 2ea79ed2e0..77906d1857 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -61,6 +61,10 @@ glm::mat4 StereoDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProje return eyeProjection; } +glm::mat4 StereoDisplayPlugin::getEyePose(Eye eye) const { + return mat4(); +} + std::vector _screenActions; void StereoDisplayPlugin::activate() { auto screens = qApp->screens(); diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h index 33b0b09b0d..86f35c1260 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h @@ -21,14 +21,7 @@ public: virtual float getRecommendedAspectRatio() const override; virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; - - // NOTE, because Stereo displays don't include head tracking, and therefore - // can't include roll or pitch, the eye separation is embedded into the projection - // matrix. However, this eliminates the possibility of easily mainpulating - // the IPD at the Application level, the way we now allow with HMDs. - // If that becomes an issue then we'll need to break up the functionality similar - // to the HMD plugins. - // virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; + virtual glm::mat4 getEyePose(Eye eye) const override; protected: void updateScreen(); diff --git a/libraries/plugins/src/plugins/PluginContainer.cpp b/libraries/plugins/src/plugins/PluginContainer.cpp index 8afac745f3..b27f076eb6 100644 --- a/libraries/plugins/src/plugins/PluginContainer.cpp +++ b/libraries/plugins/src/plugins/PluginContainer.cpp @@ -9,17 +9,7 @@ static PluginContainer* INSTANCE{ nullptr }; -PluginContainer& PluginContainer::getInstance() { - Q_ASSERT(INSTANCE); - return *INSTANCE; -} - PluginContainer::PluginContainer() { Q_ASSERT(!INSTANCE); INSTANCE = this; }; - -PluginContainer::~PluginContainer() { - Q_ASSERT(INSTANCE == this); - INSTANCE = nullptr; -}; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index f013bfe3bf..f938758161 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -13,13 +13,10 @@ class QAction; class QGLWidget; class QScreen; -class DisplayPlugin; class PluginContainer { public: - static PluginContainer& getInstance(); PluginContainer(); - virtual ~PluginContainer(); virtual void addMenu(const QString& menuName) = 0; virtual void removeMenu(const QString& menuName) = 0; virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; @@ -32,5 +29,4 @@ public: virtual void requestReset() = 0; virtual QGLWidget* getPrimarySurface() = 0; virtual bool isForeground() = 0; - virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; };