void UpdateReticle(GameObject previousGazedObject)
    {
        if (gazePointer == null)
        {
            return;
        }

        eventCamera = pointerData.enterEventCamera ?? eventCamera; // Get the camera

        GameObject gazeObject           = GetCurrentGameObject();  // Get the gaze target
        Vector3    intersectionPosition = GetIntersectionPosition();
        bool       isInteractive        = (pointerData.pointerPress != null) ||
                                          ExecuteEvents.GetEventHandler <IPointerClickHandler>(gazeObject) != null;

        if (gazeObject == previousGazedObject)
        {
            if (gazeObject != null)
            {
                float progress = 0;
                if (isInteractive && fuseState != FuseState.Triggered)
                {
                    float delta = Time.unscaledTime - gazeStartTime;
                    progress = Mathf.Clamp01(delta / fuseTime);
                    if ((fuseState == FuseState.Arming) && (delta >= fuseTime))
                    {
                        fuseState = FuseState.Trigger;
                    }
                }
                gazePointer.OnGazeStay(eventCamera, gazeObject, intersectionPosition, progress, isInteractive);
            }
        }
        else
        {
            if (previousGazedObject != null)
            {
                gazePointer.OnGazeExit(eventCamera, previousGazedObject);
                gazeStartTime = 0;
                fuseState     = FuseState.Idle;
            }
            if (gazeObject != null)
            {
                gazePointer.OnGazeStart(eventCamera, gazeObject, intersectionPosition, isInteractive);
                gazeStartTime = Time.unscaledTime;
                GazeBehaviourModifier gbm = gazeObject.GetComponent <GazeBehaviourModifier>();
                fuseTime  = (gbm != null) && (gbm.fuseTimeOverride > 0) ? gbm.fuseTimeOverride : defaultFuseTime;
                fuseState = FuseState.Arming;
            }
        }
    }
    private void CastRayFromGaze()
    {
        if (gazePointer == null)
        {
            return;
        }

        Vector2 headPose = (eventCamera == null) ? Vector2.zero : NormalizedCartesianToSpherical(eventCamera.transform.forward);

        if (pointerData == null)
        {
            pointerData  = new PointerEventData(eventSystem);
            lastHeadPose = headPose;
        }

        // Cast a ray into the scene
        pointerData.Reset();
        pointerData.position = pointerPos;
        eventSystem.RaycastAll(pointerData, m_RaycastResultCache);

        // discard every hit too far away or too close
        for (int idx = m_RaycastResultCache.Count - 1; idx >= 0; idx--)
        {
            RaycastResult r = m_RaycastResultCache[idx];

            // what are the limits of the gaze pointer
            float min, max;
            gazePointer.GetDistanceLimits(out min, out max);

            // consider gaze behaviour modifiers
            GazeBehaviourModifier gbm = (r.gameObject != null) ? r.gameObject.GetComponent <GazeBehaviourModifier>() : null;
            min = (gbm != null) && (gbm.minimumGazeRangeOverride > 0) ? gbm.minimumGazeRangeOverride : min;
            max = (gbm != null) && (gbm.maximumGazeRangeOverride > 0) ? gbm.maximumGazeRangeOverride : max;

            if ((r.distance > max) || (r.distance < min))
            {
                m_RaycastResultCache.RemoveAt(idx);
            }
        }

        pointerData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
        m_RaycastResultCache.Clear();
        pointerData.delta = headPose - lastHeadPose;
        lastHeadPose      = headPose;
    }