void CallEnterEvents() { if (tracker_hover_next == null) { return; } if (tracker_hover == null) { tracker_hover_next.OnEnter(this); tracker_hover = tracker_hover_next; } Debug.Assert(tracker_hover == tracker_hover_next); if (is_clicking_now && !is_grabbing) { switch (clicking_button) { case EControllerButton.Trigger: tracker_hover.OnTriggerDown(this); break; case EControllerButton.Grip: tracker_hover.OnGripDown(this); break; } grabbing_button = clicking_button; is_grabbing = true; } }
void CallLeaveEvents() { if (tracker_hover != null && tracker_hover != tracker_hover_next) { BaseControllerTracker prev = tracker_hover; tracker_hover = null; prev.OnLeave(this); SetPointer(null); } }
static void CallControllerMoves(Controller[] controllers) { Debug.Assert(controllers.Length == 2); /* for now, always exactly two */ BaseControllerTracker left_tracker = controllers[0].tracker_hover; BaseControllerTracker right_tracker = controllers[1].tracker_hover; if (left_tracker == right_tracker) { if (left_tracker == null) { return; /* both controllers are nowhere */ } if (left_tracker is ConcurrentControllerTracker) { /* both controllers are over the same ConcurrentControllerTracker */ (left_tracker as ConcurrentControllerTracker).OnMove(FilterNotLeaving(controllers)); return; } } foreach (var ctrl in controllers) { BaseControllerTracker tracker = ctrl.tracker_hover; if (tracker is ControllerTracker) { if (ctrl.is_grabbing) { switch (ctrl.grabbing_button) { case EControllerButton.Trigger: (tracker as ControllerTracker).OnTriggerDrag(ctrl); break; case EControllerButton.Grip: (tracker as ControllerTracker).OnGripDrag(ctrl); break; } } else { (tracker as ControllerTracker).OnMoveOver(ctrl); } } else if (tracker is ConcurrentControllerTracker) { (tracker as ConcurrentControllerTracker).OnMove(FilterNotLeaving(new Controller[] { ctrl })); } } }
void ReadControllerState() { /* updates the state fields; updates 'is_tracking' and 'is_clicking_now'; * may cause un-grabbing and so 'is_grabbing' may be reset to false; * sets 'tracker_hover_next'. */ is_clicking_now = false; var system = OpenVR.System; if (system == null || !isActiveAndEnabled || !system.GetControllerState((uint)trackedObject.index, ref controllerState, (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(VRControllerState_t)))) { tracker_hover_next = null; bitmask_buttons = 0; if (is_tracking) { if (is_grabbing) { UnGrab(); } is_tracking = false; ResetVelocityEstimates(); } } else { is_tracking = true; /* read the button state */ ulong trigger = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_SteamVR_Trigger)); ulong pad = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_SteamVR_Touchpad)); ulong grip = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_Grip)); ulong menu = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_ApplicationMenu)); uint b = 0; if (menu != 0) { b |= (1U << (int)EControllerButton.Menu); } if (grip != 0) { if (!GetButton(EControllerButton.Grip)) { is_clicking_now = true; clicking_button = EControllerButton.Grip; } b |= (1U << (int)EControllerButton.Grip); } if (pad != 0) { b |= (1U << (int)EControllerButton.Touchpad); } if (trigger != 0) { if (!GetButton(EControllerButton.Trigger)) { is_clicking_now = true; clicking_button = EControllerButton.Trigger; } b |= (1U << (int)EControllerButton.Trigger); } bitmask_buttons = b; if (is_grabbing && grabbing_button.HasValue && !GetButton(grabbing_button.Value)) { UnGrab(); } /* read the position/rotation and update the velocity estimation */ current_position = transform.position + transform.rotation * POS_TO_CURSOR; current_rotation = transform.rotation; UpdateVelocityEstimates(); /* find the next BaseControllerTracker at that position, taking the highest * priority one. If is_grabbing, then keep the current one instead. */ if (is_grabbing) { tracker_hover_next = tracker_hover; tracker_hover_next_priority = float.PositiveInfinity; } else { Collider[] lst = Physics.OverlapSphere(current_position, 0.02f, Physics.AllLayers, QueryTriggerInteraction.Collide); var potential = new HashSet <Transform>(); foreach (var coll in lst) { Transform tr = coll.transform; while (tr != null) { if (!potential.Add(tr)) { break; /* already in the set */ } tr = tr.parent; } } float best_priority = float.NegativeInfinity; BaseControllerTracker best = null; foreach (Transform tr in potential) { foreach (var tracker in tr.GetComponents <BaseControllerTracker>()) { if (tracker is ControllerTracker && !Matches((tracker as ControllerTracker).selectableControllers)) { continue; } float priority = tracker.GetPriority(this); if (priority == float.NegativeInfinity) { continue; } Debug.Assert(priority < float.PositiveInfinity); if (priority > best_priority || (priority == best_priority && tracker.creation_order > best.creation_order)) { best_priority = priority; best = tracker; } } } tracker_hover_next = best; tracker_hover_next_priority = best_priority; } /* sanity check */ if (is_grabbing) { Debug.Assert(tracker_hover); } } }
void Update() { if (active_controller == null) { foreach (var ctrl in BaroqueUI.GetControllers()) { if (ctrl.Matches(controllerSelection) && ctrl.GetButton(controllerButton)) { BaseControllerTracker tracker = ctrl.HoverControllerTracker(); if (tracker == null || tracker.CanStartTeleportAction(ctrl)) { arc.Show(); active_controller = ctrl; break; } } } if (active_controller == null) { return; } } if (active_controller.GetButton(controllerButton)) { bool saved = Physics.queriesHitTriggers; try { Physics.queriesHitTriggers = false; Transform tr = active_controller.transform; arc.SetArcData(tr.position, tr.TransformDirection(new Vector3(0, beamUpVelocity, beamForwardVelocity)), true, false); destination_valid = false; bool show_invalid = false; RaycastHit hitInfo; if (arc.DrawArc(out hitInfo)) { /* The teleport destination is accepted if we fit a capsule here. More precisely: * the capsule starts at ABOVE_GROUND above the hit point of the beam; on top * of that we check the capsule. The height of that capsule above around is thus * from ABOVE_GROUND to ABOVE_GROUND + RADIUS + DISTANCE + RADIUS. The parameters * are chosen so that planes of above ~30° cannot be teleported to, because the * bottom of the capsule always intersects that plane. */ const float ABOVE_GROUND = 0.1f, RADIUS = 0.32f, DISTANCE = 1.1f; if (Physics.CheckCapsule(hitInfo.point + (ABOVE_GROUND + RADIUS) * Vector3.up, hitInfo.point + (ABOVE_GROUND + RADIUS + DISTANCE) * Vector3.up, RADIUS, traceLayerMask, QueryTriggerInteraction.Ignore)) { /* invalid position */ invalid_reticle.position = hitInfo.point; invalid_reticle.rotation = Quaternion.LookRotation(hitInfo.normal) * Quaternion.Euler(90, 0, 0); show_invalid = true; } else { /* valid position */ invalid_reticle.gameObject.SetActive(false); destination_reticle.position = destination_position = hitInfo.point; destination_valid = true; } } invalid_reticle.gameObject.SetActive(show_invalid); destination_reticle.gameObject.SetActive(destination_valid); arc.SetColor(destination_valid ? validArcColor : invalidArcColor); } finally { Physics.queriesHitTriggers = saved; } } else { active_controller = null; arc.Hide(); invalid_reticle.gameObject.SetActive(false); destination_reticle.gameObject.SetActive(false); if (destination_valid) { StartTeleporting(); } } }