using RioJoy.Core.Calibration;
namespace RioJoy.Core.Output;
///
/// A resolved axis write: which pad control to drive and the converted value.
/// is in the thumb range (-32768..32767) for thumb
/// targets, the trigger range (0..255) for trigger targets, and 0 for
/// (nothing is written).
///
public readonly struct ResolvedAxis
{
public PadTarget Target { get; }
public int Value { get; }
public ResolvedAxis(PadTarget target, int value)
{
Target = target;
Value = value;
}
public override string ToString() => $"{Target}:{Value}";
}
///
/// Pure route-resolution + value-conversion for the ViGEm sink — no ViGEm types,
/// so the decision logic is unit-testable without the bus driver.
/// translates the result into ViGEm calls.
///
public static class AxisRouter
{
///
/// Resolve where the calibrated (0..32766,
/// center 16383) of lands under
/// , and convert it for that target.
///
public static ResolvedAxis Resolve(AxisRoutingConfig config, JoyAxis axis, int value)
{
if (config is null) throw new ArgumentNullException(nameof(config));
AxisRoute route = config.RouteFor(axis);
return route.Target switch
{
PadTarget.None => new ResolvedAxis(PadTarget.None, 0),
PadTarget.LeftTrigger or PadTarget.RightTrigger =>
new ResolvedAxis(route.Target, ToTrigger(value)),
_ => new ResolvedAxis(
route.Target,
route.Mode == AxisOutputMode.UnipolarPositive
? ToUnipolarThumb(value)
: ToCenteredThumb(value)),
};
}
// RIO axis 0..32766 (centre 16383) -> Xbox thumb short -32768..32767 (legacy math).
private static int ToCenteredThumb(int value) =>
Compat.Net48Math.Clamp((value - AxisOutputs.Center) * 2, (int)short.MinValue, short.MaxValue);
// Unipolar RIO axis (rest = 0) -> upper thumb half: 0 -> center 0, 32766 -> max.
private static int ToUnipolarThumb(int value) =>
Compat.Net48Math.Clamp(value, 0, (int)short.MaxValue);
// RIO axis 0..32766 -> Xbox trigger byte 0..255 (legacy math).
private static int ToTrigger(int value) =>
Compat.Net48Math.Clamp(value * 255 / AxisOutputs.Max, 0, 255);
}