From 5eff12af34f8a047afa58dfd088faa171fc4c837 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 6 Jan 2017 18:09:23 -0700 Subject: [PATCH 1/8] add hover effect to PAL --- scripts/system/pal.js | 55 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index ef16889035..6428749bee 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -19,9 +19,13 @@ const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avata const SELECTED_TEXTURES = { "idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png"), "idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png") }; +const HOVER_TEXTURES = { "idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-hover.png"), + "idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-hover.png") +}; const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6}; -const SELECTED_COLOR = {red: 0xf3, green: 0x91, blue: 0x29}; +const SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29}; +const HOVER_COLOR = {red: 0xFF, green: 0xFF, blue: 0xFF}; // white for now (function() { // BEGIN LOCAL_SCOPE @@ -46,6 +50,7 @@ function ExtendedOverlay(key, type, properties, selected, hasModel) { // A wrapp } this.key = key; this.selected = selected || false; // not undefined + this.hovering = false; this.activeOverlay = Overlays.addOverlay(type, properties); // We could use different overlays for (un)selected... } // Instance methods: @@ -58,20 +63,38 @@ ExtendedOverlay.prototype.editOverlay = function (properties) { // change displa Overlays.editOverlay(this.activeOverlay, properties); }; -function color(selected) { - return selected ? SELECTED_COLOR : UNSELECTED_COLOR; +function color(selected, hovering) { + + return hovering ? HOVER_COLOR : selected ? SELECTED_COLOR : UNSELECTED_COLOR; } -function textures(selected) { - return selected ? SELECTED_TEXTURES : UNSELECTED_TEXTURES; +function textures(selected, hovering) { + return hovering ? HOVER_TEXTURES : selected ? SELECTED_TEXTURES : UNSELECTED_TEXTURES; +} +// so we don't have to traverse the overlays to get the last one +var lastHoveringId = 0; +ExtendedOverlay.prototype.hover = function (hovering) { + if (this.key === lastHoveringId) { + if (hovering) { + return; + } else { + lastHoveringId = 0; + } + } + this.editOverlay({color: color(this.selected, hovering)}); + if (this.model) { + this.model.editOverlay({textures: textures(this.selected, hovering)}); + } + if (hovering) { + lastHoveringId = this.key; + } } - ExtendedOverlay.prototype.select = function (selected) { if (this.selected === selected) { return; } - this.editOverlay({color: color(selected)}); + this.editOverlay({color: color(selected, this.hovering)}); if (this.model) { this.model.editOverlay({textures: textures(selected)}); } @@ -93,9 +116,12 @@ ExtendedOverlay.some = function (iterator) { // Bails early as soon as iterator } } }; -ExtendedOverlay.applyPickRay = function (pickRay, cb) { // cb(overlay) on the one overlay intersected by pickRay, if any. +ExtendedOverlay.applyPickRay = function (pickRay, cb, noHit) { // cb(overlay) on the one overlay intersected by pickRay, if any. var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. if (!pickedOverlay.intersects) { + if (noHit) { + return noHit(); + } return; } ExtendedOverlay.some(function (overlay) { // See if pickedOverlay is one of ours. @@ -311,6 +337,7 @@ function updateOverlays() { } function removeOverlays() { selectedIds = []; + lastHoveringId = 0; HighlightedEntity.clearOverlays(); ExtendedOverlay.some(function (overlay) { overlay.deleteOverlay(); }); } @@ -332,6 +359,16 @@ function handleMouseEvent(mousePressEvent) { // handleClick if we get one. } handleClick(Camera.computePickRay(mousePressEvent.x, mousePressEvent.y)); } +function handleMouseMoveEvent(event) { + // find out which overlay (if any) is over the mouse position + // var overlayAtPoint = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + var pickRay = Camera.computePickRay(event.x, event.y); + var hit = ExtendedOverlay.applyPickRay(pickRay, function (overlay) { + overlay.hover(true); + }, function () { + ExtendedOverlay.some(function (overlay) { overlay.hover(false); }); + }); +} // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we don't get mousePressEvents. var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); @@ -371,6 +408,7 @@ function off() { if (isWired) { // It is not ok to disconnect these twice, hence guard. Script.update.disconnect(updateOverlays); Controller.mousePressEvent.disconnect(handleMouseEvent); + Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); isWired = false; } triggerMapping.disable(); // It's ok if we disable twice. @@ -385,6 +423,7 @@ function onClicked() { isWired = true; Script.update.connect(updateOverlays); Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); } else { off(); From 409e785aa3d4baeac8d7eb70d5ab5852aeffb77c Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 9 Jan 2017 08:42:43 -0700 Subject: [PATCH 2/8] fix un-hover, add some comments --- scripts/system/pal.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 6428749bee..72955bf3ab 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -86,6 +86,10 @@ ExtendedOverlay.prototype.hover = function (hovering) { this.model.editOverlay({textures: textures(this.selected, hovering)}); } if (hovering) { + // un-hover the last hovering overlay + if (lastHoveringId && lastHoveringId != this.key) { + ExtendedOverlay.get(lastHoveringId).hover(false); + } lastHoveringId = this.key; } } @@ -116,7 +120,10 @@ ExtendedOverlay.some = function (iterator) { // Bails early as soon as iterator } } }; -ExtendedOverlay.applyPickRay = function (pickRay, cb, noHit) { // cb(overlay) on the one overlay intersected by pickRay, if any. + +// hit(overlay) on the one overlay intersected by pickRay, if any. +// noHit() if no ExtendedOverlay was intersected (helps with hover) +ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { // cb(overlay) on the one overlay intersected by pickRay, if any. var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. if (!pickedOverlay.intersects) { if (noHit) { @@ -126,7 +133,7 @@ ExtendedOverlay.applyPickRay = function (pickRay, cb, noHit) { // cb(overlay) on } ExtendedOverlay.some(function (overlay) { // See if pickedOverlay is one of ours. if ((overlay.activeOverlay) === pickedOverlay.overlayID) { - cb(overlay); + hit(overlay); return true; } }); @@ -363,7 +370,7 @@ function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position // var overlayAtPoint = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); var pickRay = Camera.computePickRay(event.x, event.y); - var hit = ExtendedOverlay.applyPickRay(pickRay, function (overlay) { + ExtendedOverlay.applyPickRay(pickRay, function (overlay) { overlay.hover(true); }, function () { ExtendedOverlay.some(function (overlay) { overlay.hover(false); }); From 5c6ae6fe95ca1a6d71799f139f8d7484173a8dad Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 10 Jan 2017 14:47:34 -0700 Subject: [PATCH 3/8] HMD hover working now Had to hack a bit -- the trigger mappings were not firing so instead I just get the hand that is triggering (when HMD is active) and handle the hover almost as before, with mouse move events. Some thought about how to map a 'mouse move' event into something where 2 triggers can both be pressed at same time was in order. --- scripts/system/pal.js | 71 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 6a9ac1195b..ef65fb0a88 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -120,6 +120,11 @@ ExtendedOverlay.some = function (iterator) { // Bails early as soon as iterator } } }; +ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId (if any) + if (lastHoveringId) { + ExtendedOverlay.get(lastHoveringId).hover(false); + } +}; // hit(overlay) on the one overlay intersected by pickRay, if any. // noHit() if no ExtendedOverlay was intersected (helps with hover) @@ -366,16 +371,70 @@ function handleMouseEvent(mousePressEvent) { // handleClick if we get one. } handleClick(Camera.computePickRay(mousePressEvent.x, mousePressEvent.y)); } -function handleMouseMoveEvent(event) { - // find out which overlay (if any) is over the mouse position - // var overlayAtPoint = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - var pickRay = Camera.computePickRay(event.x, event.y); +function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position + if (HMD.active) { + var hand = whichHand(); + if (hand != 0) { + print("pick ray for " + hand); + pickRay = controllerComputePickRay(hand); + } else { + // nothing should hover, so + ExtendedOverlay.unHover(); + return; + } + } else { + pickRay = Camera.computePickRay(event.x, event.y); + } + handleMouseMove(pickRay); +} +const TRIGGER_THRESHOLD = 0.85; +// for some reason, I could not get trigger mappings for the LT and RT to fire. So, since we can read the +// value of the RT and LT, and the messages come through as mouse moves, we have the hack below to figure out +// which hand is being triggered, and compute the pick ray accordingly. +// +function isPressed(hand) { // helper to see if the hand passed in has the trigger pulled + var controller = (hand === Controller.Standard.RightHand ? Controller.Standard.RT : Controller.Standard.LT); + return Controller.getValue(controller) > TRIGGER_THRESHOLD; +} +// helpful globals +var currentHandPressed = 0; +var hands = [Controller.Standard.RightHand, Controller.Standard.LeftHand]; + +function whichHand() { + // for HMD, decide which hand is the "mouse". The 'logic' is to use the first one that + // is triggered, until that one is released. There are interesting effects when both + // are held that this avoids. Mapping the 2 triggers and their lasers to one mouse move + // message is a bit problematic, this mitigates some of it. + if (HMD.active) { + var pressed = {}; + for (var i = 0; i 0.85) { + if (clicked > TRIGGER_THRESHOLD) { var pickRay = controllerComputePickRay(hand); handleClick(pickRay); } From 2d55ed265807eafa43a7d23cd34957ba848f90af Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 10 Jan 2017 15:51:24 -0700 Subject: [PATCH 4/8] Fix hover - probably my merge didn't get this line --- scripts/system/pal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 05d8194c08..9104e96350 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -78,6 +78,7 @@ function textures(selected, hovering) { // so we don't have to traverse the overlays to get the last one var lastHoveringId = 0; ExtendedOverlay.prototype.hover = function (hovering) { + this.hovering = hovering; if (this.key === lastHoveringId) { if (hovering) { return; From 5fd11ade9cfbe9445480b947d2c4c16fd3627281 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 10 Jan 2017 16:00:19 -0700 Subject: [PATCH 5/8] minor tweak to hover color for glow effect --- scripts/system/pal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 9104e96350..d385b5331e 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -25,7 +25,7 @@ const HOVER_TEXTURES = { "idle-D": Script.resolvePath("./assets/models/Avatar-Ov const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6}; const SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29}; -const HOVER_COLOR = {red: 0xFF, green: 0xFF, blue: 0xFF}; // white for now +const HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now (function() { // BEGIN LOCAL_SCOPE From 4fade3a53eb07db6d2b7d980c832b99194ea606d Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 10 Jan 2017 16:12:02 -0700 Subject: [PATCH 6/8] CR feedback --- scripts/system/pal.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index d385b5331e..d45e1fc7bc 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -133,7 +133,7 @@ ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId // hit(overlay) on the one overlay intersected by pickRay, if any. // noHit() if no ExtendedOverlay was intersected (helps with hover) -ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { // cb(overlay) on the one overlay intersected by pickRay, if any. +ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. if (!pickedOverlay.intersects) { if (noHit) { @@ -377,6 +377,13 @@ function handleMouseEvent(mousePressEvent) { // handleClick if we get one. } handleClick(Camera.computePickRay(mousePressEvent.x, mousePressEvent.y)); } +function handleMouseMove(pickRay) { // given the pickRay, just do the hover logic + ExtendedOverlay.applyPickRay(pickRay, function (overlay) { + overlay.hover(true); + }, function () { + ExtendedOverlay.unHover(); + }); +} function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position if (HMD.active) { var hand = whichHand(); @@ -433,14 +440,6 @@ function whichHand() { return currentHandPressed; } -function handleMouseMove(pickRay) { // given the pickRay, just do the hover logic - ExtendedOverlay.applyPickRay(pickRay, function (overlay) { - overlay.hover(true); - }, function () { - ExtendedOverlay.unHover(); - }); -} - // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we don't get mousePressEvents. var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); From 0a018e133dfcf63e80a54da41474165dd024d38d Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 10 Jan 2017 18:23:39 -0700 Subject: [PATCH 7/8] Blue laser should be enough to hover --- scripts/system/pal.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index d45e1fc7bc..ef3e37101a 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -400,14 +400,15 @@ function handleMouseMoveEvent(event) { // find out which overlay (if any) is ove } handleMouseMove(pickRay); } -const TRIGGER_THRESHOLD = 0.85; +const TRIGGER_CLICK_THRESHOLD = 0.85; +const TRIGGER_PRESS_THRESHOLD = 0.05; // for some reason, I could not get trigger mappings for the LT and RT to fire. So, since we can read the // value of the RT and LT, and the messages come through as mouse moves, we have the hack below to figure out // which hand is being triggered, and compute the pick ray accordingly. // function isPressed(hand) { // helper to see if the hand passed in has the trigger pulled var controller = (hand === Controller.Standard.RightHand ? Controller.Standard.RT : Controller.Standard.LT); - return Controller.getValue(controller) > TRIGGER_THRESHOLD; + return Controller.getValue(controller) > TRIGGER_PRESS_THRESHOLD; } // helpful globals var currentHandPressed = 0; @@ -451,7 +452,7 @@ function controllerComputePickRay(hand) { } function makeClickHandler(hand) { return function (clicked) { - if (clicked > TRIGGER_THRESHOLD) { + if (clicked > TRIGGER_CLICK_THRESHOLD) { var pickRay = controllerComputePickRay(hand); handleClick(pickRay); } From 1e3a00d1fbb621548e20d856833c411972bb8dc9 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 11 Jan 2017 14:43:37 -0700 Subject: [PATCH 8/8] Enable the LT and RT signals, use them A bit cleaner. Still have to keep track of which hand is the mouse, but this removes some of the hacky code. --- scripts/system/pal.js | 75 ++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index ef3e37101a..48f44570fd 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -384,12 +384,16 @@ function handleMouseMove(pickRay) { // given the pickRay, just do the hover logi ExtendedOverlay.unHover(); }); } + +// handy global to keep track of which hand is the mouse (if any) +var currentHandPressed = 0; +const TRIGGER_CLICK_THRESHOLD = 0.85; +const TRIGGER_PRESS_THRESHOLD = 0.05; + function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position if (HMD.active) { - var hand = whichHand(); - if (hand != 0) { - print("pick ray for " + hand); - pickRay = controllerComputePickRay(hand); + if (currentHandPressed != 0) { + pickRay = controllerComputePickRay(currentHandPressed); } else { // nothing should hover, so ExtendedOverlay.unHover(); @@ -400,50 +404,27 @@ function handleMouseMoveEvent(event) { // find out which overlay (if any) is ove } handleMouseMove(pickRay); } -const TRIGGER_CLICK_THRESHOLD = 0.85; -const TRIGGER_PRESS_THRESHOLD = 0.05; -// for some reason, I could not get trigger mappings for the LT and RT to fire. So, since we can read the -// value of the RT and LT, and the messages come through as mouse moves, we have the hack below to figure out -// which hand is being triggered, and compute the pick ray accordingly. -// -function isPressed(hand) { // helper to see if the hand passed in has the trigger pulled - var controller = (hand === Controller.Standard.RightHand ? Controller.Standard.RT : Controller.Standard.LT); - return Controller.getValue(controller) > TRIGGER_PRESS_THRESHOLD; -} -// helpful globals -var currentHandPressed = 0; -var hands = [Controller.Standard.RightHand, Controller.Standard.LeftHand]; - -function whichHand() { - // for HMD, decide which hand is the "mouse". The 'logic' is to use the first one that - // is triggered, until that one is released. There are interesting effects when both - // are held that this avoids. Mapping the 2 triggers and their lasers to one mouse move - // message is a bit problematic, this mitigates some of it. - if (HMD.active) { - var pressed = {}; - for (var i = 0; i TRIGGER_PRESS_THRESHOLD; + if (currentHandPressed == 0) { + currentHandPressed = isPressed ? hand : 0; + return; } - return currentHandPressed; + if (currentHandPressed == hand) { + currentHandPressed = isPressed ? hand : 0; + return; + } + // otherwise, the other hand is still triggered + // so do nothing. } // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we don't get mousePressEvents. var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); +var triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); function controllerComputePickRay(hand) { var controllerPose = getControllerWorldLocation(hand, true); if (controllerPose.valid) { @@ -458,9 +439,15 @@ function makeClickHandler(hand) { } }; } +function makePressHandler(hand) { + return function (value) { + handleTriggerPressed(hand, value); + } +} triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand)); triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); - +triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); +triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); // // Manage the connection between the button and the window. // @@ -484,6 +471,7 @@ function off() { isWired = false; } triggerMapping.disable(); // It's ok if we disable twice. + triggerPressMapping.disable(); // see above removeOverlays(); Users.requestsDomainListData = false; } @@ -497,6 +485,7 @@ function onClicked() { Controller.mousePressEvent.connect(handleMouseEvent); Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); + triggerPressMapping.enable(); } else { off(); }