// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
using UltimateXR.Core.Math;
using UnityEngine;
namespace UltimateXR.Avatar.Rig
{
///
/// Stores information of an avatar rig's finger.
///
[Serializable]
public class UxrAvatarFingerInfo
{
#region Inspector Properties/Serialized Fields
[SerializeField] private UxrAvatar _avatar;
[SerializeField] private UxrHandSide _side;
[SerializeField] private UxrFingerType _finger;
[SerializeField] private UxrAvatarFingerBoneInfo _metacarpalInfo;
[SerializeField] private UxrAvatarFingerBoneInfo _proximalInfo;
[SerializeField] private UxrAvatarFingerBoneInfo _intermediateInfo;
[SerializeField] private UxrAvatarFingerBoneInfo _distalInfo;
[SerializeField] private Vector3 _distalLocalTip;
[SerializeField] private Vector3 _distalLocalFingerPrintCenter;
#endregion
#region Public Types & Data
///
/// Gets the metacarpal bone info.
///
public UxrAvatarFingerBoneInfo MetacarpalInfo => _metacarpalInfo;
///
/// Gets the proximal bone info.
///
public UxrAvatarFingerBoneInfo ProximalInfo => _proximalInfo;
///
/// Gets the intermediate bone info.
///
public UxrAvatarFingerBoneInfo IntermediateInfo => _intermediateInfo;
///
/// Gets the distal bone info.
///
public UxrAvatarFingerBoneInfo DistalInfo => _distalInfo;
///
/// Gets the finger tip in local coordinates of the distal bone.
///
public Vector3 DistalLocalTip => _distalLocalTip;
///
/// Gets an approximate position of the finger print center in local coordinates of the distal bone. The position is
/// computed as a position at 2/3 of the distance between the distal bone start and the tip and at the bottom part of
/// the distal using the distal radius.
///
public Vector3 DistalLocalFingerPrintCenter => _distalLocalFingerPrintCenter;
///
/// Gets the tip position in world-space.
///
public Vector3 TipPosition
{
get
{
if (_avatar)
{
UxrAvatarFinger avatarFinger = _avatar.GetHand(_side).GetFinger(_finger);
if (avatarFinger.Distal)
{
return avatarFinger.Distal.TransformPoint(_distalLocalTip);
}
}
return Vector3.zero;
}
}
///
/// Gets the tip forward direction in world-space.
///
public Vector3 TipDirection
{
get
{
if (_avatar)
{
UxrAvatarFinger avatarFinger = _avatar.GetHand(_side).GetFinger(_finger);
if (avatarFinger.Distal)
{
UxrUniversalLocalAxes fingerAxes = _avatar.AvatarRigInfo.GetArmInfo(_side).FingerUniversalLocalAxes;
return avatarFinger.Distal.TransformVector(fingerAxes.LocalForward);
}
}
return Vector3.zero;
}
}
///
/// Gets the finger print approximate position. The position is computed as a position at 2/3 of the distance between
/// the distal bone start and the tip and at the bottom part of the distal using the distal radius.
///
public Vector3 FingerPrintPosition
{
get
{
if (_avatar)
{
UxrAvatarFinger avatarFinger = _avatar.GetHand(_side).GetFinger(_finger);
if (avatarFinger.Distal)
{
return avatarFinger.Distal.TransformPoint(_distalLocalFingerPrintCenter);
}
}
return Vector3.zero;
}
}
///
/// Gets the finger print direction in world-space. The direction points from the finger print center downwards.
///
public Vector3 FingerPrintDirection
{
get
{
if (_avatar)
{
UxrAvatarFinger avatarFinger = _avatar.GetHand(_side).GetFinger(_finger);
if (avatarFinger.Distal)
{
UxrUniversalLocalAxes fingerAxes = _avatar.AvatarRigInfo.GetArmInfo(_side).FingerUniversalLocalAxes;
return -avatarFinger.Distal.TransformVector(fingerAxes.LocalUp);
}
}
return Vector3.zero;
}
}
#endregion
#region Internal Methods
///
/// Computes the finger information.
///
/// Avatar whose finger information to compute
/// Hand renderer
/// Which hand side the finger belongs to
/// Which finger to compute
internal void Compute(UxrAvatar avatar, SkinnedMeshRenderer handRenderer, UxrHandSide side, UxrFingerType finger)
{
_avatar = avatar;
_side = side;
_finger = finger;
UxrUniversalLocalAxes fingerAxes = avatar.AvatarRigInfo.GetArmInfo(side).FingerUniversalLocalAxes;
UxrAvatarFinger avatarFinger = avatar.GetHand(side).GetFinger(finger);
_metacarpalInfo = new UxrAvatarFingerBoneInfo();
_proximalInfo = new UxrAvatarFingerBoneInfo();
_intermediateInfo = new UxrAvatarFingerBoneInfo();
_distalInfo = new UxrAvatarFingerBoneInfo();
_metacarpalInfo.Compute(handRenderer, avatarFinger.Metacarpal, avatarFinger.Proximal, fingerAxes);
_proximalInfo.Compute(handRenderer, avatarFinger.Proximal, avatarFinger.Intermediate, fingerAxes);
_intermediateInfo.Compute(handRenderer, avatarFinger.Intermediate, avatarFinger.Distal, fingerAxes);
_distalInfo.Compute(handRenderer, avatarFinger.Distal, null, fingerAxes);
_distalLocalTip = fingerAxes.LocalForward * _distalInfo.Length;
_distalLocalFingerPrintCenter = fingerAxes.LocalForward * (_distalInfo.Length * 0.66f) - fingerAxes.LocalUp * (_distalInfo.Radius * 0.66f);
}
#endregion
}
}