/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// A nr pointer raycaster.
[DisallowMultipleComponent]
public class NRPointerRaycaster : EventCameraRaycaster
{
/// Values that represent mask type enums.
public enum MaskTypeEnum
{
/// An enum constant representing the inclusive option.
Inclusive,
/// An enum constant representing the exclusive option.
Exclusive
}
/// The hits.
private static readonly RaycastHit[] hits = new RaycastHit[64];
/// Type of the mask.
public MaskTypeEnum maskType = MaskTypeEnum.Exclusive;
/// The mask.
public LayerMask mask;
/// Gets the raycast mask.
/// The raycast mask.
public int raycastMask { get { return maskType == MaskTypeEnum.Inclusive ? (int)mask : ~mask; } }
/// True to show, false to hide the debug ray.
public bool showDebugRay = true;
/// True to enable, false to disable the physics raycast.
public bool enablePhysicsRaycast = true;
/// True to enable, false to disable the graphic raycast.
public bool enableGraphicRaycast = true;
/// List of button event data.
protected readonly List buttonEventDataList = new List();
/// The sorted raycast results.
protected readonly List sortedRaycastResults = new List();
/// The break points.
protected readonly List breakPoints = new List();
/// Temporary raycast results.
private readonly List temporaryRaycastResults = new List();
/// The related hand.
private ControllerHandEnum m_RelatedHand;
/// Gets or sets the related hand.
/// The related hand.
public ControllerHandEnum RelatedHand
{
get
{
return NRInput.RaycastMode == RaycastModeEnum.Gaze ? NRInput.DomainHand : m_RelatedHand;
}
internal set
{
m_RelatedHand = value;
}
}
/// Gets the break points.
/// The break points.
public List BreakPoints { get { return breakPoints; } }
/// Gets information describing the hover event.
/// Information describing the hover event.
public NRPointerEventData HoverEventData { get { return buttonEventDataList.Count > 0 ? buttonEventDataList[0] : null; } }
/// Gets a list of button event data.
/// A list of button event data.
private ReadOnlyCollection readonlyButtonEventDataList;
public ReadOnlyCollection ButtonEventDataList
{
get
{
if (readonlyButtonEventDataList == null)
readonlyButtonEventDataList = buttonEventDataList.AsReadOnly();
return readonlyButtonEventDataList;
}
}
/// See MonoBehaviour.Start.
protected override void Start()
{
base.Start();
buttonEventDataList.Add(new NRPointerEventData(this, EventSystem.current));
}
/// called by StandaloneInputModule, not supported.
/// Information describing the event.
/// List of result appends.
public override void Raycast(PointerEventData eventData, List resultAppendList)
{
}
/// Raycasts.
public virtual void Raycast()
{
sortedRaycastResults.Clear();
breakPoints.Clear();
var zScale = transform.lossyScale.z;
var amountDistance = (FarDistance - NearDistance) * zScale;
if (!gameObject.activeInHierarchy)
{
amountDistance = 0.0001f;
}
var origin = transform.TransformPoint(0f, 0f, NearDistance);
breakPoints.Add(origin);
Vector3 direction;
float distance;
Ray ray;
RaycastResult firstHit = default(RaycastResult);
direction = transform.forward;
distance = amountDistance;
ray = new Ray(origin, direction);
eventCamera.farClipPlane = eventCamera.nearClipPlane + distance;
eventCamera.transform.position = ray.origin - (ray.direction * eventCamera.nearClipPlane);
eventCamera.transform.rotation = Quaternion.LookRotation(ray.direction, transform.up);
Raycast(ray, distance, sortedRaycastResults);
firstHit = FirstRaycastResult();
breakPoints.Add(firstHit.isValid ? firstHit.worldPosition : ray.GetPoint(distance));
#if UNITY_EDITOR
if (showDebugRay)
{
Debug.DrawLine(breakPoints[0], breakPoints[1], firstHit.isValid ? Color.green : Color.red);
}
#endif
}
/// Gets raycaster result comparer.
/// The raycaster result comparer.
protected virtual Comparison GetRaycasterResultComparer()
{
return NRInputModule.defaultRaycastComparer;
}
///
/// override OnEnable & OnDisable on purpose so that this BaseRaycaster won't be registered into
/// RaycasterManager.
protected override void OnEnable()
{
//base.OnEnable();
NRInputModule.AddRaycaster(this);
}
/// See MonoBehaviour.OnDisable.
protected override void OnDisable()
{
//base.OnDisable();
NRInputModule.RemoveRaycaster(this);
}
/// Gets scroll delta.
/// The scroll delta.
public virtual Vector2 GetScrollDelta()
{
return Vector2.zero;
}
/// First raycast result.
/// A RaycastResult.
public RaycastResult FirstRaycastResult()
{
for (int i = 0, imax = sortedRaycastResults.Count; i < imax; ++i)
{
if (!sortedRaycastResults[i].isValid)
continue;
return sortedRaycastResults[i];
}
return default(RaycastResult);
}
/// Raycasts.
/// The ray.
/// The distance.
/// The raycast results.
public void Raycast(Ray ray, float distance, List raycastResults)
{
temporaryRaycastResults.Clear();
if (enablePhysicsRaycast)
{
PhysicsRaycast(ray, distance, temporaryRaycastResults);
}
if (enableGraphicRaycast)
{
var tempCanvases = CanvasTargetCollector.GetCanvases();
for (int i = tempCanvases.Count - 1; i >= 0; --i)
{
var target = tempCanvases[i];
if (target == null || !target.enabled)
continue;
GraphicRaycast(target, target.ignoreReversedGraphics, ray, distance, this, temporaryRaycastResults);
}
}
var comparer = GetRaycasterResultComparer();
if (comparer != null)
{
temporaryRaycastResults.Sort(comparer);
}
for (int i = 0, imax = temporaryRaycastResults.Count; i < imax; ++i)
{
raycastResults.Add(temporaryRaycastResults[i]);
}
}
/// Physics raycast.
/// The ray.
/// The distance.
/// The raycast results.
public virtual void PhysicsRaycast(Ray ray, float distance, List raycastResults)
{
var hitCount = Physics.RaycastNonAlloc(ray, hits, distance, raycastMask);
for (int i = 0; i < hitCount; ++i)
{
raycastResults.Add(new RaycastResult
{
gameObject = hits[i].collider.gameObject,
module = this,
distance = hits[i].distance,
worldPosition = hits[i].point,
worldNormal = hits[i].normal,
screenPosition = NRInputModule.ScreenCenterPoint,
index = raycastResults.Count,
sortingLayer = 0,
sortingOrder = 0
});
}
}
/// Graphic raycast.
/// The canvas.
/// True to ignore reversed graphics.
/// The ray.
/// The distance.
/// The raycaster.
/// The raycast results.
public virtual void GraphicRaycast(ICanvasRaycastTarget raycastTarget, bool ignoreReversedGraphics, Ray ray, float distance, NRPointerRaycaster raycaster, List raycastResults)
{
if (raycastTarget.canvas == null)
return;
var eventCamera = raycaster.eventCamera;
var screenCenterPoint = NRInputModule.ScreenCenterPoint;
raycastTarget.GraphicRaycast(ignoreReversedGraphics, ray, distance, screenCenterPoint, raycaster, raycastResults);
}
}
}