// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
using UltimateXR.Core.Components.Composite;
using UnityEngine;
namespace UltimateXR.Animation.IK
{
///
/// Base IK Solver class. IK solvers should inherit from it and override the method.
/// Not all solvers need to be part of an avatar, but the inheritance is used to
/// be able to enumerate all the solvers that are part of an avatar.
///
public abstract class UxrIKSolver : UxrAvatarComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] private bool _enabled = true;
[SerializeField] private bool _manualUpdate;
#endregion
#region Public Types & Data
///
/// Called right before the IK is about to be solved during the current frame
///
public event Action Solving;
///
/// Called right after the IK was solved during the current frame
///
public event Action Solved;
///
/// Gets whether the component is initialized.
///
public abstract bool Initialized { get; }
///
/// Gets if the solver needs to be updated automatically.
///
public bool NeedsAutoUpdate => gameObject.activeInHierarchy && enabled && SolverEnabled && !ManualUpdate;
///
/// Gets or sets the IK solver enabled state?
///
public bool SolverEnabled
{
get => _enabled;
set => _enabled = value;
}
///
/// Gets if the IK solver will update itself. Otherwise the user will be responsible of calling .
///
public bool ManualUpdate
{
get => _manualUpdate;
set => _manualUpdate = value;
}
#endregion
#region Public Methods
///
/// Solves the IK. Calls ,which is implemented in child classes, but calls the
/// appropriate and events.
///
public void SolveIK()
{
Solving?.Invoke();
InternalSolveIK();
Solved?.Invoke();
}
#endregion
#region Unity
///
/// Subscribes to events
///
protected override void OnEnable()
{
base.OnEnable();
UxrManager.StageUpdating += UxrManager_StageUpdating;
}
///
/// Unsubscribes from events
///
protected override void OnDisable()
{
base.OnDisable();
UxrManager.StageUpdating -= UxrManager_StageUpdating;
}
#endregion
#region Event Handling Methods
///
/// Will solve the IK chain in case it is not part of an avatar. If it is part of a VR avatar, the VR avatar will take
/// care of calling the SolveIK method so that it is processed in the correct order, after the hands are updated.
///
private void UxrManager_StageUpdating(UxrUpdateStage stage)
{
if (stage == UxrUpdateStage.PostProcess && Avatar == null && NeedsAutoUpdate)
{
SolveIK();
}
}
#endregion
#region Protected Methods
///
/// To be implemented in child classes to execute the actual IK solving algorithm for the current frame
///
protected abstract void InternalSolveIK();
#endregion
}
}