From 4d8f33f9bbc70f2929bf71d30b417df83ea26f54 Mon Sep 17 00:00:00 2001
From: Kevin Lee <kevin@infinite-lee.com>
Date: Thu, 19 Apr 2018 18:57:38 -0700
Subject: [PATCH] Add teleport to gaze-only cursor

---
 src/components/cursor-controller.js | 64 +++++++++++++++++++----------
 src/hub.html                        | 17 ++++++--
 src/input-mappings.js               |  4 +-
 3 files changed, 60 insertions(+), 25 deletions(-)

diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js
index aa54b3e95..3840aa6a6 100644
--- a/src/components/cursor-controller.js
+++ b/src/components/cursor-controller.js
@@ -8,8 +8,9 @@ AFRAME.registerComponent("cursor-controller", {
   schema: {
     cursor: { type: "selector" },
     camera: { type: "selector" },
-    controller: { type: "selector" },
     playerRig: { type: "selector" },
+    gazeTeleportControls: { type: "selector" },
+    controller: { type: "string" },
     otherHand: { type: "string" },
     hand: { default: "right" },
     trackedControls: { type: "string", default: "[tracked-controls]" },
@@ -39,6 +40,7 @@ AFRAME.registerComponent("cursor-controller", {
     this.point = new THREE.Vector3();
     this.mousePos = new THREE.Vector2();
     this.controllerQuaternion = new THREE.Quaternion();
+    this.controller = null;
 
     this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered });
 
@@ -69,13 +71,17 @@ AFRAME.registerComponent("cursor-controller", {
 
   update: function(oldData) {
     if (this.data.controller !== oldData.controller) {
-      if (oldData.controller) {
-        oldData.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener);
-        oldData.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener);
+      if (this.controller) {
+        this.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener);
+        this.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener);
       }
 
-      this.data.controller.addEventListener(this.data.controllerEvent, this.controllerEventListener);
-      this.data.controller.addEventListener(this.data.controllerEndEvent, this.controllerEndEventListener);
+      this.controller = document.querySelector(this.data.controller);
+
+      if (this.controller) {
+        this.controller.addEventListener(this.data.controllerEvent, this.controllerEventListener);
+        this.controller.addEventListener(this.data.controllerEndEvent, this.controllerEndEventListener);
+      }
     }
 
     if (oldData.otherHand && this.data.otherHand !== oldData.otherHand) {
@@ -131,8 +137,10 @@ AFRAME.registerComponent("cursor-controller", {
     this.el.removeEventListener("raycaster-intersection", this.raycasterIntersectionListener);
     this.el.removeEventListener("raycaster-intersection-cleared", this.raycasterIntersectionClearedListener);
 
-    this.data.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener);
-    this.data.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener);
+    if (this.controller) {
+      this.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener);
+      this.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener);
+    }
 
     this.data.playerRig.removeEventListener("model-loaded", this.modelLoadedListener);
 
@@ -153,21 +161,22 @@ AFRAME.registerComponent("cursor-controller", {
 
     if (this.wasOtherHandGrabbing) return;
 
+    //set raycaster origin/direction
     const camera = this.data.camera.components.camera.camera;
     if (!this.inVR && !this.isMobile) {
-      //mouse
+      //mouse cursor mode
       const raycaster = this.el.components.raycaster.raycaster;
       raycaster.setFromCamera(this.mousePos, camera);
       this.origin = raycaster.ray.origin;
       this.direction = raycaster.ray.direction;
     } else if ((this.inVR || this.isMobile) && !this.hasPointingDevice) {
-      //gaze
+      //gaze cursor mode
       camera.getWorldPosition(this.origin);
       camera.getWorldDirection(this.direction);
     } else {
-      //3d
-      this.data.controller.object3D.getWorldPosition(this.origin);
-      this.data.controller.object3D.getWorldQuaternion(this.controllerQuaternion);
+      //3d cursor mode
+      this.controller.object3D.getWorldPosition(this.origin);
+      this.controller.object3D.getWorldQuaternion(this.controllerQuaternion);
       this.direction
         .set(0, 0, -1)
         .applyQuaternion(this.controllerQuaternion)
@@ -178,6 +187,7 @@ AFRAME.registerComponent("cursor-controller", {
 
     let intersection = null;
 
+    //update cursor position
     if (!this.isGrabbing) {
       const intersections = this.el.components.raycaster.intersections;
       if (intersections.length > 0 && intersections[0].distance <= this.data.maxDistance) {
@@ -199,7 +209,10 @@ AFRAME.registerComponent("cursor-controller", {
       this.data.cursor.object3D.position.copy(this.point);
     }
 
-    if (intersection) {
+    //update currentTargetType
+    if (this.isGrabbing && !intersection) {
+      this.currentTargetType = TARGET_TYPE_INTERACTABLE;
+    } else if (intersection) {
       if (this._isInteractableAllowed() && this._isClass("interactable", intersection.object.el)) {
         this.currentTargetType = TARGET_TYPE_INTERACTABLE;
       } else if (this._isClass("ui", intersection.object.el)) {
@@ -209,6 +222,7 @@ AFRAME.registerComponent("cursor-controller", {
       this.currentTargetType = TARGET_TYPE_NONE;
     }
 
+    //update cursor material
     const isTarget = this._isTargetOfType(TARGET_TYPE_INTERACTABLE_OR_UI);
     if ((this.isGrabbing || isTarget) && !this.wasIntersecting) {
       this.wasIntersecting = true;
@@ -218,6 +232,7 @@ AFRAME.registerComponent("cursor-controller", {
       this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered });
     }
 
+    //update line
     if (this.hasPointingDevice) {
       this.el.setAttribute("line", { start: this.origin.clone(), end: this.data.cursor.object3D.position.clone() });
     }
@@ -250,23 +265,29 @@ AFRAME.registerComponent("cursor-controller", {
   },
 
   _startTeleport: function() {
+    const hideCursor = !(this.hasPointingDevice || this.inVR);
     if (this.hasPointingDevice) {
-      this.data.controller.emit(this.data.teleportEvent, {});
-      this.el.setAttribute("line", { visible: false });
-      this.data.cursor.setAttribute("visible", false);
+      this.controller.emit(this.data.teleportEvent, {});
+    } else if (this.inVR) {
+      this.data.gazeTeleportControls.emit(this.data.teleportEvent, {});
     }
+    this.el.setAttribute("line", { visible: hideCursor });
+    this.data.cursor.setAttribute("visible", hideCursor);
   },
 
   _endTeleport: function() {
+    const showCursor = this.hasPointingDevice || this.inVR;
     if (this.hasPointingDevice) {
-      this.data.controller.emit(this.data.teleportEndEvent, {});
-      this.el.setAttribute("line", { visible: true });
-      this.data.cursor.setAttribute("visible", true);
+      this.controller.emit(this.data.teleportEndEvent, {});
+    } else if (this.inVR) {
+      this.data.gazeTeleportControls.emit(this.data.teleportEndEvent, {});
     }
+    this.el.setAttribute("line", { visible: showCursor });
+    this.data.cursor.setAttribute("visible", showCursor);
   },
 
   _handleMouseDown: function() {
-    if (this._isTargetOfType(TARGET_TYPE_INTERACTABLE)) {
+    if (this._isTargetOfType(TARGET_TYPE_INTERACTABLE_OR_UI)) {
       const lookControls = this.data.camera.components["look-controls"];
       if (lookControls) lookControls.pause();
       this.data.cursor.emit(this.data.controllerEvent, {});
@@ -343,5 +364,6 @@ AFRAME.registerComponent("cursor-controller", {
 
   _handleCursorLoaded: function() {
     this.data.cursor.object3DMap.mesh.renderOrder = 1;
+    this.el.quer;
   }
 });
diff --git a/src/hub.html b/src/hub.html
index afa09451e..4c1186977 100644
--- a/src/hub.html
+++ b/src/hub.html
@@ -146,14 +146,15 @@
                 camera: #player-camera; 
                 controller: #player-right-controller;
                 playerRig: #player-rig;
-                otherHand: #right-super-hand;"
+                otherHand: #right-super-hand;
+                gazeTeleportControls: #gaze-teleport;"
             raycaster="objects: .collidable, .interactable, .ui; far: 3;"
             line="visible: false; color: white; opacity: 0.2;"
         ></a-entity>
 
         <a-sphere
             id="cursor"
-            material="depthTest: false;"
+            material="depthTest: false; opacity:0.9;"
             radius="0.02"
             static-body="shape: sphere;"
             collision-filter="collisionForces: false"
@@ -198,7 +199,17 @@
                 camera
                 position="0 1.6 0"
                 personal-space-bubble="radius: 0.4"
-            ></a-entity>
+            >
+                <a-entity
+                    id="gaze-teleport"
+                    position = "0.15 0 0"
+                    teleport-controls="
+                    cameraRig: #player-rig; 
+                    teleportOrigin: #player-camera; 
+                    button: action_teleport_; 
+                    collisionEntities: [nav-mesh]"
+                ></a-entity>
+            </a-entity>
 
             <a-entity
                 id="player-left-controller"
diff --git a/src/input-mappings.js b/src/input-mappings.js
index 09160b0ec..b692e173f 100644
--- a/src/input-mappings.js
+++ b/src/input-mappings.js
@@ -94,7 +94,9 @@ const config = {
         trackpad_dpad4_pressed_center_down: ["action_primary_down"],
         trackpad_dpad4_pressed_north_down: ["action_primary_down"],
         trackpad_dpad4_pressed_south_down: ["action_primary_down"],
-        trackpadup: ["action_primary_up"]
+        trackpadup: ["action_primary_up"],
+        triggerdown: ["action_primary_down"],
+        triggerup: ["action_primary_up"]
       },
       keyboard: {
         m_press: "action_mute",
-- 
GitLab