// Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. using System; using System.Collections.Generic; using System.Linq; namespace Meta.XR.Movement.FaceTracking.Samples { /// /// Mapper class. Used by to map from /// weights provider names to drivers (or blendshapes on character). /// public class Mapper { private class Rule { public int FirstIndex; public int SecondIndex; public Rule(int first, int second) { FirstIndex = first; SecondIndex = second; } } private readonly Rule[] _rules; private readonly int _expectedSrcSize, _expectedDstSize; /// /// Main constructor where source and destination names are mapped to each other and stored. /// /// Source names. /// Destination names. /// Warning in case source name is not found in destination. /// Warning if any names rename in destination after mapping has completed. public Mapper(IList src, IList dest, Action> warnIfSrcNotFound, Action> warnIfDestNotDriven) { _expectedSrcSize = src.Count; _expectedDstSize = dest.Count; var notFound = new SortedSet(); var remainderInDest = dest.ToHashSet(); if (src.Count == 0) { foreach (var s in src) { notFound.Add(s); } } if (dest.Count > 0 && src.Count > 0) { List rules = new List(); for (var i = 0; i < src.Count; ++i) { var index = dest.IndexOf(src[i]); if (index < 0) { notFound.Add(src[i]); } else { rules.Add(new Rule(i, index)); remainderInDest.Remove(dest[index]); } } _rules = rules.ToArray(); } if (notFound.Count > 0 && warnIfSrcNotFound != null) { warnIfSrcNotFound(notFound); } if (remainderInDest.Count > 0 && warnIfDestNotDriven != null) { warnIfDestNotDriven(remainderInDest); } } /// /// Uses stored mapping to map from source to destination. /// /// Source values. /// Destination values. /// Exception thrown if a problem is encountered. public void Map(float[] src, float[] dest) { if (src.Length != _expectedSrcSize) { throw new ArgumentException($"Expected source to be of length {_expectedSrcSize}, got {src.Length}"); } if (dest.Length != _expectedDstSize) { throw new ArgumentException($"Expected destination to be of length {_expectedDstSize}, got {dest.Length}"); } foreach (var t in _rules) { dest[t.SecondIndex] = src[t.FirstIndex]; } } } }