Merge branch 'master' of https://github.com/highfidelity/hifi into loginInitiative2

This commit is contained in:
Wayne Chen 2018-12-10 09:18:21 -08:00
commit 9e4c93c95d
19 changed files with 346 additions and 106 deletions

View file

@ -3278,3 +3278,7 @@ void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properti
properties.setOwningAvatarID(getOwningAvatarID()); properties.setOwningAvatarID(getOwningAvatarID());
setLastBroadcast(now); // for debug/physics status icons setLastBroadcast(now); // for debug/physics status icons
} }
bool EntityItem::isWearable() const {
return isVisible() && (getParentID() == DependencyManager::get<NodeList>()->getSessionUUID() || getParentID() == AVATAR_SELF_ID);
}

View file

@ -489,7 +489,7 @@ public:
void scriptHasUnloaded(); void scriptHasUnloaded();
void setScriptHasFinishedPreload(bool value); void setScriptHasFinishedPreload(bool value);
bool isScriptPreloadFinished(); bool isScriptPreloadFinished();
virtual bool isWearable() const;
bool isDomainEntity() const { return _hostType == entity::HostType::DOMAIN; } bool isDomainEntity() const { return _hostType == entity::HostType::DOMAIN; }
bool isAvatarEntity() const { return _hostType == entity::HostType::AVATAR; } bool isAvatarEntity() const { return _hostType == entity::HostType::AVATAR; }
bool isLocalEntity() const { return _hostType == entity::HostType::LOCAL; } bool isLocalEntity() const { return _hostType == entity::HostType::LOCAL; }

View file

@ -114,6 +114,8 @@ bool EntityScriptingInterface::canReplaceContent() {
void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
if (_entityTree) { if (_entityTree) {
disconnect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity);
disconnect(_entityTree.get(), &EntityTree::deletingEntityPointer, this, &EntityScriptingInterface::onDeletingEntity);
disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
disconnect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); disconnect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
disconnect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); disconnect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
@ -122,6 +124,8 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
_entityTree = elementTree; _entityTree = elementTree;
if (_entityTree) { if (_entityTree) {
connect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity, Qt::DirectConnection);
connect(_entityTree.get(), &EntityTree::deletingEntityPointer, this, &EntityScriptingInterface::onDeletingEntity, Qt::DirectConnection);
connect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); connect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
connect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); connect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
connect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); connect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
@ -1060,7 +1064,17 @@ void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer
} }
} }
void EntityScriptingInterface::onAddingEntity(EntityItem* entity) {
if (entity->isWearable()) {
emit addingWearable(entity->getEntityItemID());
}
}
void EntityScriptingInterface::onDeletingEntity(EntityItem* entity) {
if (entity->isWearable()) {
emit deletingWearable(entity->getEntityItemID());
}
}
QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
PROFILE_RANGE(script_entities, __FUNCTION__); PROFILE_RANGE(script_entities, __FUNCTION__);

View file

@ -1908,6 +1908,31 @@ signals:
*/ */
void addingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID);
/**jsdoc
* Triggered when an 'wearable' entity is deleted.
* @function Entities.deletingWearable
* @param {Uuid} entityID - The ID of the 'wearable' entity deleted.
* @returns {Signal}
* @example <caption>Report when an 'wearable' entity is deleted.</caption>
* Entities.deletingWearable.connect(function (entityID) {
* print("Deleted wearable: " + entityID);
* });
*/
void deletingWearable(const EntityItemID& entityID);
/**jsdoc
* Triggered when an 'wearable' entity is added to Interface's local in-memory tree of entities it knows about. This may occur when
* 'wearable' entities are added to avatar
* @function Entities.addingWearable
* @param {Uuid} entityID - The ID of the 'wearable' entity added.
* @returns {Signal}
* @example <caption>Report when an 'wearable' entity is added.</caption>
* Entities.addingWearable.connect(function (entityID) {
* print("Added wearable: " + entityID);
* });
*/
void addingWearable(const EntityItemID& entityID);
/**jsdoc /**jsdoc
* Triggered when you disconnect from a domain, at which time Interface's local in-memory tree of entities it knows about * Triggered when you disconnect from a domain, at which time Interface's local in-memory tree of entities it knows about
* is cleared. * is cleared.
@ -1938,6 +1963,8 @@ protected:
private slots: private slots:
void handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode); void handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode);
void onAddingEntity(EntityItem* entity);
void onDeletingEntity(EntityItem* entity);
private: private:
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor); bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor);

View file

@ -305,6 +305,7 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
fixupNeedsParentFixups(); fixupNeedsParentFixups();
emit addingEntity(entity->getEntityItemID()); emit addingEntity(entity->getEntityItemID());
emit addingEntityPointer(entity.get());
} }
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) { bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {

View file

@ -309,6 +309,7 @@ signals:
void deletingEntity(const EntityItemID& entityID); void deletingEntity(const EntityItemID& entityID);
void deletingEntityPointer(EntityItem* entityID); void deletingEntityPointer(EntityItem* entityID);
void addingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID);
void addingEntityPointer(EntityItem* entityID);
void editingEntityPointer(const EntityItemPointer& entityID); void editingEntityPointer(const EntityItemPointer& entityID);
void entityScriptChanging(const EntityItemID& entityItemID, const bool reload); void entityScriptChanging(const EntityItemID& entityItemID, const bool reload);
void entityServerScriptChanging(const EntityItemID& entityItemID, const bool reload); void entityServerScriptChanging(const EntityItemID& entityItemID, const bool reload);

View file

@ -519,7 +519,6 @@ QVector<bool> ModelEntityItem::getJointTranslationsSet() const {
return result; return result;
} }
bool ModelEntityItem::hasModel() const { bool ModelEntityItem::hasModel() const {
return resultWithReadLock<bool>([&] { return resultWithReadLock<bool>([&] {
return !_modelURL.isEmpty(); return !_modelURL.isEmpty();

View file

@ -31,6 +31,8 @@ static const QUrl DEFAULT_SCRIPTS_LOCATION { "file:///~//defaultScripts.js" };
// Using a QVariantList so this is human-readable in the settings file // Using a QVariantList so this is human-readable in the settings file
static Setting::Handle<QVariantList> runningScriptsHandle(SETTINGS_KEY, { QVariant(DEFAULT_SCRIPTS_LOCATION) }); static Setting::Handle<QVariantList> runningScriptsHandle(SETTINGS_KEY, { QVariant(DEFAULT_SCRIPTS_LOCATION) });
const int RELOAD_ALL_SCRIPTS_TIMEOUT = 1000;
ScriptsModel& getScriptsModel() { ScriptsModel& getScriptsModel() {
static ScriptsModel scriptsModel; static ScriptsModel scriptsModel;
@ -387,15 +389,10 @@ void ScriptEngines::stopAllScripts(bool restart) {
// queue user scripts if restarting // queue user scripts if restarting
if (restart && scriptEngine->isUserLoaded()) { if (restart && scriptEngine->isUserLoaded()) {
_isReloading = true; _isReloading = true;
bool lastScript = (it == _scriptEnginesHash.constEnd() - 1);
ScriptEngine::Type type = scriptEngine->getType(); ScriptEngine::Type type = scriptEngine->getType();
connect(scriptEngine.data(), &ScriptEngine::finished, this, [this, type, lastScript] (QString scriptName) { connect(scriptEngine.data(), &ScriptEngine::finished, this, [this, type] (QString scriptName) {
reloadScript(scriptName, true)->setType(type); reloadScript(scriptName, true)->setType(type);
if (lastScript) {
_isReloading = false;
}
}); });
} }
@ -405,6 +402,9 @@ void ScriptEngines::stopAllScripts(bool restart) {
if (restart) { if (restart) {
qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading"; qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading";
QTimer::singleShot(RELOAD_ALL_SCRIPTS_TIMEOUT, this, [&] {
_isReloading = false;
});
emit scriptsReloading(); emit scriptsReloading();
} }
} }

View file

@ -69,12 +69,12 @@ function getMyAvatarSettings() {
} }
} }
function updateAvatarWearables(avatar, bookmarkAvatarName, callback) { function updateAvatarWearables(avatar, callback) {
executeLater(function() { executeLater(function() {
var wearables = getMyAvatarWearables(); var wearables = getMyAvatarWearables();
avatar[ENTRY_AVATAR_ENTITIES] = wearables; avatar[ENTRY_AVATAR_ENTITIES] = wearables;
sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables, 'avatarName' : bookmarkAvatarName}) sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables})
if(callback) if(callback)
callback(); callback();
@ -188,7 +188,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
sendToQml(message) sendToQml(message)
break; break;
case 'selectAvatar': case 'selectAvatar':
Entities.addingWearable.disconnect(onAddingWearable);
Entities.deletingWearable.disconnect(onDeletingWearable);
AvatarBookmarks.loadBookmark(message.name); AvatarBookmarks.loadBookmark(message.name);
Entities.addingWearable.connect(onAddingWearable);
Entities.deletingWearable.connect(onDeletingWearable);
break; break;
case 'deleteAvatar': case 'deleteAvatar':
AvatarBookmarks.removeBookmark(message.name); AvatarBookmarks.removeBookmark(message.name);
@ -223,7 +227,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
// revert changes using snapshot of wearables // revert changes using snapshot of wearables
if(currentAvatarWearablesBackup !== null) { if(currentAvatarWearablesBackup !== null) {
AvatarBookmarks.updateAvatarEntities(currentAvatarWearablesBackup); AvatarBookmarks.updateAvatarEntities(currentAvatarWearablesBackup);
updateAvatarWearables(currentAvatar, message.avatarName); updateAvatarWearables(currentAvatar);
} }
} else { } else {
sendToQml({'method' : 'updateAvatarInBookmarks'}); sendToQml({'method' : 'updateAvatarInBookmarks'});
@ -256,8 +260,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
parentJointIndex: hipsIndex parentJointIndex: hipsIndex
}; };
Entities.addingWearable.disconnect(onAddingWearable);
var entityID = Entities.addEntity(properties, true); var entityID = Entities.addEntity(properties, true);
updateAvatarWearables(currentAvatar, message.avatarName, function() { Entities.addingWearable.connect(onAddingWearable);
updateAvatarWearables(currentAvatar, function() {
onSelectedEntity(entityID); onSelectedEntity(entityID);
}); });
break; break;
@ -265,8 +272,12 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
ensureWearableSelected(message.entityID); ensureWearableSelected(message.entityID);
break; break;
case 'deleteWearable': case 'deleteWearable':
Entities.deletingWearable.disconnect(onDeletingWearable);
Entities.deleteEntity(message.entityID); Entities.deleteEntity(message.entityID);
updateAvatarWearables(currentAvatar, message.avatarName); Entities.deletingWearable.connect(onDeletingWearable);
updateAvatarWearables(currentAvatar);
break; break;
case 'changeDisplayName': case 'changeDisplayName':
if (MyAvatar.displayName !== message.displayName) { if (MyAvatar.displayName !== message.displayName) {
@ -380,6 +391,18 @@ function onSelectedEntity(entityID, pointerEvent) {
} }
} }
function onAddingWearable(entityID) {
updateAvatarWearables(currentAvatar, function() {
sendToQml({'method' : 'updateAvatarInBookmarks'});
});
}
function onDeletingWearable(entityID) {
updateAvatarWearables(currentAvatar, function() {
sendToQml({'method' : 'updateAvatarInBookmarks'});
});
}
function handleWearableMessages(channel, message, sender) { function handleWearableMessages(channel, message, sender) {
if (channel !== 'Hifi-Object-Manipulation') { if (channel !== 'Hifi-Object-Manipulation') {
return; return;
@ -485,6 +508,8 @@ function off() {
AvatarBookmarks.bookmarkDeleted.disconnect(onBookmarkDeleted); AvatarBookmarks.bookmarkDeleted.disconnect(onBookmarkDeleted);
AvatarBookmarks.bookmarkAdded.disconnect(onBookmarkAdded); AvatarBookmarks.bookmarkAdded.disconnect(onBookmarkAdded);
Entities.addingWearable.disconnect(onAddingWearable);
Entities.deletingWearable.disconnect(onDeletingWearable);
MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged);
MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged);
MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged);
@ -495,16 +520,23 @@ function off() {
} }
function on() { function on() {
AvatarBookmarks.bookmarkLoaded.connect(onBookmarkLoaded);
AvatarBookmarks.bookmarkDeleted.connect(onBookmarkDeleted);
AvatarBookmarks.bookmarkAdded.connect(onBookmarkAdded);
MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); if (!isWired) { // It is not ok to connect these twice, hence guard.
MyAvatar.dominantHandChanged.connect(onDominantHandChanged); isWired = true;
MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged);
MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); AvatarBookmarks.bookmarkLoaded.connect(onBookmarkLoaded);
MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); AvatarBookmarks.bookmarkDeleted.connect(onBookmarkDeleted);
MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); AvatarBookmarks.bookmarkAdded.connect(onBookmarkAdded);
Entities.addingWearable.connect(onAddingWearable);
Entities.deletingWearable.connect(onDeletingWearable);
MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged);
MyAvatar.dominantHandChanged.connect(onDominantHandChanged);
MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged);
MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl);
MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged);
MyAvatar.targetScaleChanged.connect(onTargetScaleChanged);
}
} }
function onTabletButtonClicked() { function onTabletButtonClicked() {
@ -514,7 +546,6 @@ function onTabletButtonClicked() {
} else { } else {
ContextOverlay.enabled = false; ContextOverlay.enabled = false;
tablet.loadQMLSource(AVATARAPP_QML_SOURCE); tablet.loadQMLSource(AVATARAPP_QML_SOURCE);
isWired = true;
} }
} }
var hasEventBridge = false; var hasEventBridge = false;

View file

@ -424,9 +424,19 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
} }
}; };
this.leftBlacklistTabletIDs = [];
this.rightBlacklistTabletIDs = [];
this.setLeftBlacklist = function () {
Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist.concat(_this.leftBlacklistTabletIDs));
};
this.setRightBlacklist = function () {
Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist.concat(_this.rightBlacklistTabletIDs));
};
this.setBlacklist = function() { this.setBlacklist = function() {
Pointers.setIgnoreItems(_this.leftPointer, this.blacklist); _this.setLeftBlacklist();
Pointers.setIgnoreItems(_this.rightPointer, this.blacklist); _this.setRightBlacklist();
}; };
var MAPPING_NAME = "com.highfidelity.controllerDispatcher"; var MAPPING_NAME = "com.highfidelity.controllerDispatcher";
@ -490,7 +500,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
enabled: true enabled: true
}); });
this.handleHandMessage = function(channel, data, sender) { this.handleMessage = function (channel, data, sender) {
var message; var message;
if (sender === MyAvatar.sessionUUID) { if (sender === MyAvatar.sessionUUID) {
try { try {
@ -511,6 +521,18 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
_this.setBlacklist(); _this.setBlacklist();
} }
} }
if (action === "tablet") {
var tabletIDs = message.blacklist
? [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : [];
if (message.hand === LEFT_HAND) {
_this.leftBlacklistTabletIDs = tabletIDs;
_this.setLeftBlacklist();
} else {
_this.rightBlacklistTabletIDs = tabletIDs;
_this.setRightBlacklist();
}
}
} }
} catch (e) { } catch (e) {
print("WARNING: handControllerGrab.js -- error parsing message: " + data); print("WARNING: handControllerGrab.js -- error parsing message: " + data);
@ -550,7 +572,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
var controllerDispatcher = new ControllerDispatcher(); var controllerDispatcher = new ControllerDispatcher();
Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); Messages.subscribe('Hifi-Hand-RayPick-Blacklist');
Messages.messageReceived.connect(controllerDispatcher.handleHandMessage); Messages.messageReceived.connect(controllerDispatcher.handleMessage);
Script.scriptEnding.connect(controllerDispatcher.cleanup); Script.scriptEnding.connect(controllerDispatcher.cleanup);
Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS); Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS);
}()); }());

View file

@ -48,6 +48,7 @@ Script.include("/~/system/libraries/controllers.js");
function FarActionGrabEntity(hand) { function FarActionGrabEntity(hand) {
this.hand = hand; this.hand = hand;
this.grabbing = false;
this.grabbedThingID = null; this.grabbedThingID = null;
this.targetObject = null; this.targetObject = null;
this.actionID = null; // action this script created... this.actionID = null; // action this script created...
@ -151,6 +152,7 @@ Script.include("/~/system/libraries/controllers.js");
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.previousRoomControllerPosition = roomControllerPosition; this.previousRoomControllerPosition = roomControllerPosition;
this.grabbing = true;
}; };
this.continueDistanceHolding = function(controllerData) { this.continueDistanceHolding = function(controllerData) {
@ -246,6 +248,7 @@ Script.include("/~/system/libraries/controllers.js");
this.grabbedThingID = null; this.grabbedThingID = null;
this.targetObject = null; this.targetObject = null;
this.potentialEntityWithContextOverlay = false; this.potentialEntityWithContextOverlay = false;
this.grabbing = false;
}; };
this.updateRecommendedArea = function() { this.updateRecommendedArea = function() {
@ -357,8 +360,7 @@ Script.include("/~/system/libraries/controllers.js");
}; };
this.run = function (controllerData) { this.run = function (controllerData) {
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) {
this.notPointingAtEntity(controllerData) || this.targetIsNull()) {
this.endFarGrabAction(); this.endFarGrabAction();
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity); this.highlightedEntity);
@ -375,10 +377,12 @@ Script.include("/~/system/libraries/controllers.js");
this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar",
this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity",
this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity",
this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity"
this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay",
this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"
]; ];
if (!this.grabbing) {
nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay");
nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight");
}
var nearGrabReadiness = []; var nearGrabReadiness = [];
for (var i = 0; i < nearGrabNames.length; i++) { for (var i = 0; i < nearGrabNames.length; i++) {

View file

@ -47,6 +47,7 @@ Script.include("/~/system/libraries/controllers.js");
function FarParentGrabEntity(hand) { function FarParentGrabEntity(hand) {
this.hand = hand; this.hand = hand;
this.grabbing = false;
this.targetEntityID = null; this.targetEntityID = null;
this.targetObject = null; this.targetObject = null;
this.previouslyUnhooked = {}; this.previouslyUnhooked = {};
@ -455,8 +456,7 @@ Script.include("/~/system/libraries/controllers.js");
}; };
this.run = function (controllerData) { this.run = function (controllerData) {
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) {
this.notPointingAtEntity(controllerData) || this.targetIsNull()) {
this.endFarParentGrab(controllerData); this.endFarParentGrab(controllerData);
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity);
this.highlightedEntity = null; this.highlightedEntity = null;
@ -472,10 +472,12 @@ Script.include("/~/system/libraries/controllers.js");
this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar",
this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity",
this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity",
this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity"
this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay",
this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"
]; ];
if (!this.grabbing) {
nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay");
nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight");
}
var nearGrabReadiness = []; var nearGrabReadiness = [];
for (var i = 0; i < nearGrabNames.length; i++) { for (var i = 0; i < nearGrabNames.length; i++) {
@ -485,11 +487,10 @@ Script.include("/~/system/libraries/controllers.js");
} }
if (this.targetEntityID) { if (this.targetEntityID) {
// if we are doing a distance grab and the object or tablet gets close enough to the controller, // if we are doing a distance grab and the object gets close enough to the controller,
// stop the far-grab so the near-grab or equip can take over. // stop the far-grab so the near-grab or equip can take over.
for (var k = 0; k < nearGrabReadiness.length; k++) { for (var k = 0; k < nearGrabReadiness.length; k++) {
if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.targetEntityID || if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.targetEntityID)) {
HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) {
this.endFarParentGrab(controllerData); this.endFarParentGrab(controllerData);
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }

View file

@ -37,7 +37,7 @@ Script.include("/~/system/libraries/controllers.js");
this.getTargetProps = function (controllerData) { this.getTargetProps = function (controllerData) {
var targetEntity = controllerData.rayPicks[this.hand].objectID; var targetEntity = controllerData.rayPicks[this.hand].objectID;
if (targetEntity) { if (targetEntity && controllerData.rayPicks[this.hand].type === RayPick.INTERSECTED_ENTITY) {
var targetProperties = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); var targetProperties = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES);
if (entityWantsFarTrigger(targetProperties)) { if (entityWantsFarTrigger(targetProperties)) {
return targetProperties; return targetProperties;

View file

@ -20,6 +20,7 @@ Script.include("/~/system/libraries/utils.js");
var MARGIN = 25; var MARGIN = 25;
function InEditMode(hand) { function InEditMode(hand) {
this.hand = hand; this.hand = hand;
this.isEditing = false;
this.triggerClicked = false; this.triggerClicked = false;
this.selectedTarget = null; this.selectedTarget = null;
this.reticleMinX = MARGIN; this.reticleMinX = MARGIN;
@ -62,25 +63,27 @@ Script.include("/~/system/libraries/utils.js");
return point2d; return point2d;
}; };
this.ENTITY_TOOL_UPDATES_CHANNEL = "entityToolUpdates";
this.sendPickData = function(controllerData) { this.sendPickData = function(controllerData) {
if (controllerData.triggerClicks[this.hand]) { if (controllerData.triggerClicks[this.hand]) {
var hand = this.hand === RIGHT_HAND ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var hand = this.hand === RIGHT_HAND ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
if (!this.triggerClicked) { if (!this.triggerClicked) {
this.selectedTarget = controllerData.rayPicks[this.hand]; this.selectedTarget = controllerData.rayPicks[this.hand];
if (!this.selectedTarget.intersects) { if (!this.selectedTarget.intersects) {
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({
method: "clearSelection", method: "clearSelection",
hand: hand hand: hand
})); }));
} else { } else {
if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) {
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({
method: "selectEntity", method: "selectEntity",
entityID: this.selectedTarget.objectID, entityID: this.selectedTarget.objectID,
hand: hand hand: hand
})); }));
} else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) {
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({
method: "selectOverlay", method: "selectOverlay",
overlayID: this.selectedTarget.objectID, overlayID: this.selectedTarget.objectID,
hand: hand hand: hand
@ -102,7 +105,7 @@ Script.include("/~/system/libraries/utils.js");
var desktopWindow = Window.isPointOnDesktopWindow(point2d); var desktopWindow = Window.isPointOnDesktopWindow(point2d);
var tablet = this.pointingAtTablet(rayPick.objectID); var tablet = this.pointingAtTablet(rayPick.objectID);
var rightHand = this.hand === RIGHT_HAND; var rightHand = this.hand === RIGHT_HAND;
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({
method: "pointingAt", method: "pointingAt",
desktopWindow: desktopWindow, desktopWindow: desktopWindow,
tablet: tablet, tablet: tablet,
@ -110,6 +113,10 @@ Script.include("/~/system/libraries/utils.js");
})); }));
}; };
this.runModule = function() {
return makeRunningValues(true, [], []);
};
this.exitModule = function() { this.exitModule = function() {
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
}; };
@ -120,13 +127,15 @@ Script.include("/~/system/libraries/utils.js");
this.triggerClicked = false; this.triggerClicked = false;
} }
Messages.sendLocalMessage('Hifi-unhighlight-all', ''); Messages.sendLocalMessage('Hifi-unhighlight-all', '');
return makeRunningValues(true, [], []); return this.runModule();
} }
this.triggerClicked = false; this.triggerClicked = false;
return makeRunningValues(false, [], []); return this.exitModule();
}; };
this.run = function(controllerData) { this.run = function(controllerData) {
// Tablet stylus.
var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightTabletStylusInput" : "LeftTabletStylusInput"); ? "RightTabletStylusInput" : "LeftTabletStylusInput");
if (tabletStylusInput) { if (tabletStylusInput) {
@ -136,6 +145,7 @@ Script.include("/~/system/libraries/utils.js");
} }
} }
// Tablet surface.
var webLaser = getEnabledModuleByName(this.hand === RIGHT_HAND var webLaser = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput");
if (webLaser) { if (webLaser) {
@ -147,6 +157,7 @@ Script.include("/~/system/libraries/utils.js");
} }
} }
// HUD overlay.
if (!controllerData.triggerClicks[this.hand]) { // Don't grab if trigger pressed when laser starts intersecting. if (!controllerData.triggerClicks[this.hand]) { // Don't grab if trigger pressed when laser starts intersecting.
var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightHudOverlayPointer" : "LeftHudOverlayPointer"); ? "RightHudOverlayPointer" : "LeftHudOverlayPointer");
@ -168,6 +179,7 @@ Script.include("/~/system/libraries/utils.js");
} }
} }
// Teleport.
var teleport = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter"); var teleport = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter");
if (teleport) { if (teleport) {
var teleportReady = teleport.isReady(controllerData); var teleportReady = teleport.isReady(controllerData);
@ -176,8 +188,6 @@ Script.include("/~/system/libraries/utils.js");
} }
} }
var stopRunning = false;
if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0)) { if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0)) {
var stopRunning = false; var stopRunning = false;
controllerData.nearbyOverlayIDs[this.hand].forEach(function(overlayID) { controllerData.nearbyOverlayIDs[this.hand].forEach(function(overlayID) {
@ -203,6 +213,37 @@ Script.include("/~/system/libraries/utils.js");
enableDispatcherModule("LeftHandInEditMode", leftHandInEditMode); enableDispatcherModule("LeftHandInEditMode", leftHandInEditMode);
enableDispatcherModule("RightHandInEditMode", rightHandInEditMode); enableDispatcherModule("RightHandInEditMode", rightHandInEditMode);
var INEDIT_STATUS_CHANNEL = "Hifi-InEdit-Status";
var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist";
this.handleMessage = function (channel, data, sender) {
if (channel === INEDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) {
var message;
try {
message = JSON.parse(data);
} catch (e) {
return;
}
switch (message.method) {
case "editing":
if (message.hand === LEFT_HAND) {
leftHandInEditMode.isEditing = message.editing;
} else {
rightHandInEditMode.isEditing = message.editing;
}
Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({
action: "tablet",
hand: message.hand,
blacklist: message.editing
}));
break;
}
}
};
Messages.subscribe(INEDIT_STATUS_CHANNEL);
Messages.messageReceived.connect(this.handleMessage);
function cleanup() { function cleanup() {
disableDispatcherModule("LeftHandInEditMode"); disableDispatcherModule("LeftHandInEditMode");
disableDispatcherModule("RightHandInEditMode"); disableDispatcherModule("RightHandInEditMode");

View file

@ -18,7 +18,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
function InVREditMode(hand) { function InVREditMode(hand) {
this.hand = hand; this.hand = hand;
this.disableModules = false; this.isAppActive = false;
this.isEditing = false;
this.running = false; this.running = false;
var NO_HAND_LASER = -1; // Invalid hand parameter so that standard laser is not displayed. var NO_HAND_LASER = -1; // Invalid hand parameter so that standard laser is not displayed.
this.parameters = makeDispatcherModuleParameters( this.parameters = makeDispatcherModuleParameters(
@ -66,7 +67,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}; };
this.isReady = function (controllerData) { this.isReady = function (controllerData) {
if (this.disableModules) { if (this.isAppActive) {
return makeRunningValues(true, [], []); return makeRunningValues(true, [], []);
} }
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
@ -74,14 +75,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
this.run = function (controllerData) { this.run = function (controllerData) {
// Default behavior if disabling is not enabled. // Default behavior if disabling is not enabled.
if (!this.disableModules) { if (!this.isAppActive) {
return this.exitModule(); return this.exitModule();
} }
// Tablet stylus. // Tablet stylus.
var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND ? var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND
"RightTabletStylusInput" : ? "RightTabletStylusInput" : "LeftTabletStylusInput");
"LeftTabletStylusInput");
if (tabletStylusInput) { if (tabletStylusInput) {
var tabletReady = tabletStylusInput.isReady(controllerData); var tabletReady = tabletStylusInput.isReady(controllerData);
if (tabletReady.active) { if (tabletReady.active) {
@ -90,9 +90,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
} }
// Tablet surface. // Tablet surface.
var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND
"RightWebSurfaceLaserInput" : ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput");
"LeftWebSurfaceLaserInput");
if (overlayLaser) { if (overlayLaser) {
var overlayLaserReady = overlayLaser.isReady(controllerData); var overlayLaserReady = overlayLaser.isReady(controllerData);
var target = controllerData.rayPicks[this.hand].objectID; var target = controllerData.rayPicks[this.hand].objectID;
@ -114,8 +113,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
// HUD overlay. // HUD overlay.
if (!controllerData.triggerClicks[this.hand]) { if (!controllerData.triggerClicks[this.hand]) {
var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightHudOverlayPointer" ? "RightHudOverlayPointer" : "LeftHudOverlayPointer");
: "LeftHudOverlayPointer");
if (hudLaser) { if (hudLaser) {
var hudLaserReady = hudLaser.isReady(controllerData); var hudLaserReady = hudLaser.isReady(controllerData);
if (hudLaserReady.active) { if (hudLaserReady.active) {
@ -125,9 +123,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
} }
// Teleport. // Teleport.
var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND ? var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND
"RightTeleporter" : ? "RightTeleporter" : "LeftTeleporter");
"LeftTeleporter");
if (teleporter) { if (teleporter) {
var teleporterReady = teleporter.isReady(controllerData); var teleporterReady = teleporter.isReady(controllerData);
if (teleporterReady.active) { if (teleporterReady.active) {
@ -145,19 +142,39 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
enableDispatcherModule("LeftHandInVREditMode", leftHandInVREditMode); enableDispatcherModule("LeftHandInVREditMode", leftHandInVREditMode);
enableDispatcherModule("RightHandInVREditMode", rightHandInVREditMode); enableDispatcherModule("RightHandInVREditMode", rightHandInVREditMode);
var INVREDIT_DISABLER_MESSAGE_CHANNEL = "Hifi-InVREdit-Disabler"; var INVREDIT_STATUS_CHANNEL = "Hifi-InVREdit-Status";
this.handleMessage = function (channel, message, sender) { var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist";
if (sender === MyAvatar.sessionUUID && channel === INVREDIT_DISABLER_MESSAGE_CHANNEL) { this.handleMessage = function (channel, data, sender) {
if (message === "both") { if (channel === INVREDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) {
leftHandInVREditMode.disableModules = true; var message;
rightHandInVREditMode.disableModules = true;
} else if (message === "none") { try {
leftHandInVREditMode.disableModules = false; message = JSON.parse(data);
rightHandInVREditMode.disableModules = false; } catch (e) {
return;
}
switch (message.method) {
case "active":
leftHandInVREditMode.isAppActive = message.active;
rightHandInVREditMode.isAppActive = message.active;
break;
case "editing":
if (message.hand === LEFT_HAND) {
leftHandInVREditMode.isEditing = message.editing;
} else {
rightHandInVREditMode.isEditing = message.editing;
}
Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({
action: "tablet",
hand: message.hand,
blacklist: message.editing
}));
break;
} }
} }
}; };
Messages.subscribe(INVREDIT_DISABLER_MESSAGE_CHANNEL); Messages.subscribe(INVREDIT_STATUS_CHANNEL);
Messages.messageReceived.connect(this.handleMessage); Messages.messageReceived.connect(this.handleMessage);
this.cleanup = function () { this.cleanup = function () {

View file

@ -9,7 +9,7 @@
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, /* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex,
enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings, makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings,
NEAR_GRAB_RADIUS, HMD, Uuid NEAR_GRAB_RADIUS, HMD, Uuid, getEnabledModuleByName
*/ */
Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -176,10 +176,23 @@ Script.include("/~/system/libraries/utils.js");
return null; return null;
}; };
this.isEditing = function () {
var inEditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightHandInEditMode" : "LeftHandInEditMode");
if (inEditModeModule && inEditModeModule.isEditing) {
return true;
}
var inVREditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightHandInVREditMode" : "LeftHandInVREditMode");
if (inVREditModeModule && inVREditModeModule.isEditing) {
return true;
}
return false;
};
this.isReady = function (controllerData) { this.isReady = function (controllerData) {
if ((controllerData.triggerClicks[this.hand] === 0 && if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0)
controllerData.secondaryValues[this.hand] === 0)) { || this.isEditing()) {
this.robbed = false; this.robbed = false;
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }
@ -202,7 +215,8 @@ Script.include("/~/system/libraries/utils.js");
}; };
this.run = function (controllerData) { this.run = function (controllerData) {
if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) || !this.isGrabbedThingVisible()) { if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0)
|| this.isEditing() || !this.isGrabbedThingVisible()) {
this.endNearParentingGrabOverlay(); this.endNearParentingGrabOverlay();
this.robbed = false; this.robbed = false;
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);

View file

@ -11,7 +11,7 @@
// //
/* global LEFT_HAND, RIGHT_HAND, makeDispatcherModuleParameters, makeRunningValues, enableDispatcherModule, /* global LEFT_HAND, RIGHT_HAND, makeDispatcherModuleParameters, makeRunningValues, enableDispatcherModule,
* disableDispatcherModule */ * disableDispatcherModule, getEnabledModuleByName */
Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -66,12 +66,26 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
100 100
); );
this.isEditing = function () {
var inEditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightHandInEditMode" : "LeftHandInEditMode");
if (inEditModeModule && inEditModeModule.isEditing) {
return true;
}
var inVREditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightHandInVREditMode" : "LeftHandInVREditMode");
if (inVREditModeModule && inVREditModeModule.isEditing) {
return true;
}
return false;
};
this.isNearTablet = function (controllerData) { this.isNearTablet = function (controllerData) {
return HMD.tabletID && controllerData.nearbyOverlayIDs[this.hand].indexOf(HMD.tabletID) !== -1; return HMD.tabletID && controllerData.nearbyOverlayIDs[this.hand].indexOf(HMD.tabletID) !== -1;
}; };
this.isReady = function (controllerData) { this.isReady = function (controllerData) {
if (this.isNearTablet(controllerData)) { if (!this.isEditing() && this.isNearTablet(controllerData)) {
return makeRunningValues(true, [], []); return makeRunningValues(true, [], []);
} }
setTabletNearGrabbable(this.hand, false); setTabletNearGrabbable(this.hand, false);
@ -79,7 +93,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}; };
this.run = function (controllerData) { this.run = function (controllerData) {
if (!this.isNearTablet(controllerData)) { if (this.isEditing() || !this.isNearTablet(controllerData)) {
setTabletNearGrabbable(this.hand, false); setTabletNearGrabbable(this.hand, false);
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }

View file

@ -639,6 +639,8 @@ SelectionDisplay = (function() {
ROLL: 2 ROLL: 2
}; };
const INEDIT_STATUS_CHANNEL = "Hifi-InEdit-Status";
/** /**
* The current space mode, this could have been a forced space mode since we do not support multi selection while in * The current space mode, this could have been a forced space mode since we do not support multi selection while in
* local space mode. * local space mode.
@ -985,6 +987,7 @@ SelectionDisplay = (function() {
that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press');
that.triggeredHand = NO_HAND; that.triggeredHand = NO_HAND;
that.pressedHand = NO_HAND; that.pressedHand = NO_HAND;
that.editingHand = NO_HAND;
that.triggered = function() { that.triggered = function() {
return that.triggeredHand !== NO_HAND; return that.triggeredHand !== NO_HAND;
}; };
@ -1117,6 +1120,12 @@ SelectionDisplay = (function() {
activeTool = hitTool; activeTool = hitTool;
that.clearDebugPickPlane(); that.clearDebugPickPlane();
if (activeTool.onBegin) { if (activeTool.onBegin) {
that.editingHand = that.triggeredHand;
Messages.sendLocalMessage(INEDIT_STATUS_CHANNEL, JSON.stringify({
method: "editing",
hand: that.editingHand === Controller.Standard.LeftHand ? LEFT_HAND : RIGHT_HAND,
editing: true
}));
activeTool.onBegin(event, pickRay, results); activeTool.onBegin(event, pickRay, results);
} else { } else {
print("ERROR: entitySelectionTool.mousePressEvent - ActiveTool(" + activeTool.mode + ") missing onBegin"); print("ERROR: entitySelectionTool.mousePressEvent - ActiveTool(" + activeTool.mode + ") missing onBegin");
@ -1265,6 +1274,12 @@ SelectionDisplay = (function() {
if (wantDebug) { if (wantDebug) {
print(" Triggering ActiveTool(" + activeTool.mode + ")'s onEnd"); print(" Triggering ActiveTool(" + activeTool.mode + ")'s onEnd");
} }
Messages.sendLocalMessage(INEDIT_STATUS_CHANNEL, JSON.stringify({
method: "editing",
hand: that.editingHand === Controller.Standard.LeftHand ? LEFT_HAND : RIGHT_HAND,
editing: false
}));
that.editingHand = NO_HAND;
activeTool.onEnd(event); activeTool.onEnd(event);
} else if (wantDebug) { } else if (wantDebug) {
print(" ActiveTool(" + activeTool.mode + ")'s missing onEnd"); print(" ActiveTool(" + activeTool.mode + ")'s missing onEnd");

View file

@ -251,11 +251,8 @@
} }
function getUIPositionAndRotation(hand) { function getUIPosition(hand) {
return { return MINI_POSITIONS[hand];
position: MINI_POSITIONS[hand],
rotation: MINI_ROTATIONS[hand]
};
} }
function getMiniTabletID() { function getMiniTabletID() {
@ -493,7 +490,7 @@
create(); create();
return { return {
getUIPositionAndRotation: getUIPositionAndRotation, getUIPosition: getUIPosition,
getMiniTabletID: getMiniTabletID, getMiniTabletID: getMiniTabletID,
getMiniTabletProperties: getMiniTabletProperties, getMiniTabletProperties: getMiniTabletProperties,
isLaserPointingAt: isLaserPointingAt, isLaserPointingAt: isLaserPointingAt,
@ -552,14 +549,23 @@
// Trigger values. // Trigger values.
leftTriggerOn = 0, leftTriggerOn = 0,
rightTriggerOn = 0, rightTriggerOn = 0,
MAX_TRIGGER_ON_TIME = 100, MAX_TRIGGER_ON_TIME = 400,
// Visibility. // Visibility.
MAX_HAND_CAMERA_ANGLE = 30, MAX_MEDIAL_FINGER_CAMERA_ANGLE = 25, // From palm normal along palm towards fingers.
MAX_CAMERA_HAND_ANGLE = 30, MAX_MEDIAL_WRIST_CAMERA_ANGLE = 65, // From palm normal along palm towards wrist.
MAX_LATERAL_THUMB_CAMERA_ANGLE = 25, // From palm normal across palm towards of thumb.
MAX_LATERAL_PINKY_CAMERA_ANGLE = 25, // From palm normal across palm towards pinky.
DEGREES_180 = 180, DEGREES_180 = 180,
MAX_HAND_CAMERA_ANGLE_COS = Math.cos(Math.PI * MAX_HAND_CAMERA_ANGLE / DEGREES_180), DEGREES_TO_RADIANS = Math.PI / DEGREES_180,
MAX_CAMERA_HAND_ANGLE_COS = Math.cos(Math.PI * MAX_CAMERA_HAND_ANGLE / DEGREES_180), MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_MEDIAL_FINGER_CAMERA_ANGLE,
MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_MEDIAL_WRIST_CAMERA_ANGLE,
MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_LATERAL_THUMB_CAMERA_ANGLE,
MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_LATERAL_PINKY_CAMERA_ANGLE,
MAX_CAMERA_MINI_ANGLE = 30,
MAX_CAMERA_MINI_ANGLE_COS = Math.cos(MAX_CAMERA_MINI_ANGLE * DEGREES_TO_RADIANS),
SHOWING_DELAY = 1000, // ms
lastInvisible = [0, 0],
HIDING_DELAY = 1000, // ms HIDING_DELAY = 1000, // ms
lastVisible = [0, 0]; lastVisible = [0, 0];
@ -598,11 +604,18 @@
jointIndex, jointIndex,
handPosition, handPosition,
handOrientation, handOrientation,
uiPositionAndOrientation,
miniPosition, miniPosition,
miniOrientation,
miniToCameraDirection, miniToCameraDirection,
cameraToHand; normalHandVector,
medialHandVector,
lateralHandVector,
normalDot,
medialDot,
lateralDot,
medialAngle,
lateralAngle,
cameraToMini,
now;
// Shouldn't show mini tablet if hand isn't being controlled. // Shouldn't show mini tablet if hand isn't being controlled.
pose = Controller.getPoseValue(hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand); pose = Controller.getPoseValue(hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand);
@ -647,27 +660,48 @@
Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(jointIndex))); Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(jointIndex)));
handOrientation = handOrientation =
Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(jointIndex)); Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(jointIndex));
uiPositionAndOrientation = ui.getUIPositionAndRotation(hand); var uiPosition = ui.getUIPosition(hand);
miniPosition = Vec3.sum(handPosition, Vec3.multiply(MyAvatar.sensorToWorldScale, miniPosition = Vec3.sum(handPosition, Vec3.multiply(MyAvatar.sensorToWorldScale,
Vec3.multiplyQbyV(handOrientation, uiPositionAndOrientation.position))); Vec3.multiplyQbyV(handOrientation, uiPosition)));
miniOrientation = Quat.multiply(handOrientation, uiPositionAndOrientation.rotation);
miniToCameraDirection = Vec3.normalize(Vec3.subtract(Camera.position, miniPosition)); miniToCameraDirection = Vec3.normalize(Vec3.subtract(Camera.position, miniPosition));
show = Vec3.dot(miniToCameraDirection, Quat.getForward(miniOrientation)) > MAX_HAND_CAMERA_ANGLE_COS;
show = show || (-Vec3.dot(miniToCameraDirection, Quat.getForward(handOrientation)) > MAX_HAND_CAMERA_ANGLE_COS); // Mini tablet aimed toward camera?
cameraToHand = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation)); medialHandVector = Vec3.multiplyQbyV(handOrientation, Vec3.UNIT_Y);
show = show && (cameraToHand > MAX_CAMERA_HAND_ANGLE_COS); lateralHandVector = Vec3.multiplyQbyV(handOrientation, hand === LEFT_HAND ? Vec3.UNIT_X : Vec3.UNIT_NEG_X);
normalHandVector = Vec3.multiplyQbyV(handOrientation, Vec3.UNIT_Z);
medialDot = Vec3.dot(medialHandVector, miniToCameraDirection);
lateralDot = Vec3.dot(lateralHandVector, miniToCameraDirection);
normalDot = Vec3.dot(normalHandVector, miniToCameraDirection);
medialAngle = Math.atan2(medialDot, normalDot);
lateralAngle = Math.atan2(lateralDot, normalDot);
show = -MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD <= medialAngle
&& medialAngle <= MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD
&& -MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD <= lateralAngle
&& lateralAngle <= MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD;
// Camera looking at mini tablet?
cameraToMini = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation));
show = show && (cameraToMini > MAX_CAMERA_MINI_ANGLE_COS);
// Delay showing for a while after it would otherwise be shown, unless it was showing on the other hand.
now = Date.now();
if (show) {
show = now - lastInvisible[hand] >= SHOWING_DELAY || now - lastVisible[otherHand(hand)] <= HIDING_DELAY;
} else {
lastInvisible[hand] = now;
}
// Persist showing for a while after it would otherwise be hidden. // Persist showing for a while after it would otherwise be hidden.
if (show) { if (show) {
lastVisible[hand] = Date.now(); lastVisible[hand] = now;
} else { } else {
show = Date.now() - lastVisible[hand] <= HIDING_DELAY; show = now - lastVisible[hand] <= HIDING_DELAY;
} }
} }
return { return {
show: show, show: show,
cameraToHand: cameraToHand cameraToMini: cameraToMini
}; };
} }
@ -690,7 +724,7 @@
showRight = shouldShowMini(RIGHT_HAND); showRight = shouldShowMini(RIGHT_HAND);
if (showLeft.show && showRight.show) { if (showLeft.show && showRight.show) {
// Both hands would be pointing at camera; show the one the camera is gazing at. // Both hands would be pointing at camera; show the one the camera is gazing at.
if (showLeft.cameraToHand > showRight.cameraToHand) { if (showLeft.cameraToMini > showRight.cameraToMini) {
setState(MINI_SHOWING, LEFT_HAND); setState(MINI_SHOWING, LEFT_HAND);
} else { } else {
setState(MINI_SHOWING, RIGHT_HAND); setState(MINI_SHOWING, RIGHT_HAND);
@ -752,7 +786,7 @@
showLeft = shouldShowMini(LEFT_HAND); showLeft = shouldShowMini(LEFT_HAND);
showRight = shouldShowMini(RIGHT_HAND); showRight = shouldShowMini(RIGHT_HAND);
if (showLeft.show && showRight.show) { if (showLeft.show && showRight.show) {
if (showLeft.cameraToHand > showRight.cameraToHand) { if (showLeft.cameraToMini > showRight.cameraToMini) {
if (miniHand !== LEFT_HAND) { if (miniHand !== LEFT_HAND) {
setState(MINI_HIDING); setState(MINI_HIDING);
} }