// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Avatar.Rig;
using UltimateXR.Core.Math;
using UnityEditor;
using UnityEngine;
namespace UltimateXR.Manipulation.HandPoses
{
///
/// Stores base-independent node orientations for a finger.
///
[Serializable]
public struct UxrFingerDescriptor
{
#region Inspector Properties/Serialized Fields
[SerializeField] private bool _hasMetacarpalInfo;
[SerializeField] private UxrFingerNodeDescriptor _metacarpal;
[SerializeField] private UxrFingerNodeDescriptor _proximal;
[SerializeField] private UxrFingerNodeDescriptor _proximalNoMetacarpal;
[SerializeField] private UxrFingerNodeDescriptor _intermediate;
[SerializeField] private UxrFingerNodeDescriptor _distal;
#endregion
#region Public Types & Data
///
/// Gets whether metacarpal bone information is present. Metacarpal information is optional.
///
public bool HasMetacarpalInfo => _hasMetacarpalInfo;
///
/// Gets the metacarpal bone transform information.
///
public UxrFingerNodeDescriptor Metacarpal => _metacarpal;
///
/// Gets the proximal bone transform information.
///
public UxrFingerNodeDescriptor Proximal => _proximal;
///
/// Gets the proximal bone transform information with respect to the wrist even if there is metacarpal information. It
/// is used in case a pose including metacarpal information wants to be mapped to a hand that has no metacarpal bones.
///
public UxrFingerNodeDescriptor ProximalNoMetacarpal => _proximalNoMetacarpal;
///
/// Gets the intermediate bone transform information.
///
public UxrFingerNodeDescriptor Intermediate => _intermediate;
///
/// Gets the distal bone transform information.
///
public UxrFingerNodeDescriptor Distal => _distal;
#endregion
#region Public Methods
///
/// Computes well-known axes systems for all finger bones, to handle transforms independently of the coordinate system
/// being used by a hand rig.
///
/// Wrist transform
/// Finger rig information
/// Well-known axes system for the hand
/// Well-known axes system for the finger elements
/// Whether to compute only the relative transform to the hand
public void Compute(Transform wrist, UxrAvatarFinger finger, UxrUniversalLocalAxes handLocalAxes, UxrUniversalLocalAxes fingerLocalAxes, bool computeRelativeMatrixOnly)
{
if (finger.Metacarpal)
{
_hasMetacarpalInfo = true;
_metacarpal.Compute(wrist, wrist, finger.Metacarpal, handLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
_proximal.Compute(wrist, finger.Metacarpal, finger.Proximal, fingerLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
_proximalNoMetacarpal.Compute(wrist, wrist, finger.Proximal, handLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
}
else
{
_hasMetacarpalInfo = false;
_proximal.Compute(wrist, wrist, finger.Proximal, handLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
_proximalNoMetacarpal.Compute(wrist, wrist, finger.Proximal, handLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
}
_intermediate.Compute(wrist, finger.Proximal, finger.Intermediate, fingerLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
_distal.Compute(wrist, finger.Intermediate, finger.Distal, fingerLocalAxes, fingerLocalAxes, computeRelativeMatrixOnly);
}
///
/// Mirrors the bone information, so that it can be used for the opposite hand.
///
public void Mirror()
{
if (_hasMetacarpalInfo)
{
_metacarpal.Mirror();
}
_proximal.Mirror();
_proximalNoMetacarpal.Mirror();
_intermediate.Mirror();
_distal.Mirror();
}
///
/// Interpolates the data towards another descriptor.
///
/// Descriptor to interpolate the data to
/// Interpolation factor [0.0, 1.0]
public void InterpolateTo(UxrFingerDescriptor to, float t)
{
if (_hasMetacarpalInfo)
{
_metacarpal.InterpolateTo(to._metacarpal, t);
}
_proximal.InterpolateTo(to._proximal, t);
_proximalNoMetacarpal.InterpolateTo(to._proximalNoMetacarpal, t);
_intermediate.InterpolateTo(to._intermediate, t);
_distal.InterpolateTo(to._distal, t);
}
#if UNITY_EDITOR
///
/// Outputs transform information to the editor window.
///
/// String to prefix the information with
public void DrawEditorDebugLabels(string prefix)
{
EditorGUILayout.LabelField(prefix + _proximal.Right);
EditorGUILayout.LabelField(prefix + _proximal.Up);
EditorGUILayout.LabelField(prefix + _proximal.Forward);
}
#endif
///
/// Compares the transform information with another finger.
///
/// Finger information to compare it to
/// Whether both fingers describe the same transform information
public bool Equals(UxrFingerDescriptor other)
{
if (_hasMetacarpalInfo != other._hasMetacarpalInfo)
{
return false;
}
if (_hasMetacarpalInfo)
{
return _metacarpal.Equals(other._metacarpal) && _proximal.Equals(other._proximal) && _intermediate.Equals(other._intermediate) && _distal.Equals(other._distal);
}
return _proximal.Equals(other._proximal) && _intermediate.Equals(other._intermediate) && _distal.Equals(other._distal);
}
#endregion
}
}