• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MeltyPlayer / MeltyTool / 18056332227

27 Sep 2025 06:33AM UTC coverage: 39.893% (+0.003%) from 39.89%
18056332227

push

github

MeltyPlayer
Set up simple logic for getting the union keyframes for a SeparateVector3Keyframes track. This allows us to write sparse keyframes with tangents out to GLTF, which is much more friendly to artists.

5833 of 16527 branches covered (35.29%)

Branch coverage included in aggregate %.

99 of 101 new or added lines in 2 files covered. (98.02%)

109 existing lines in 9 files now uncovered.

24587 of 59727 relevant lines covered (41.17%)

73703.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.53
/FinModelUtility/Fin/Fin/src/animation/types/vector3/SeparateVector3Keyframes.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Numerics;
5

6
using fin.animation.interpolation;
7
using fin.animation.keyframes;
8
using fin.math.floats;
9
using fin.math.interpolation;
10
using fin.util.asserts;
11

12
using NoAlloq;
13

14
namespace fin.animation.types.vector3;
15

16
public sealed class SeparateVector3Keyframes<TKeyframe>(
19,695✔
17
    ISharedInterpolationConfig sharedConfig,
19,695✔
18
    IKeyframeInterpolator<TKeyframe, float> interpolator,
19,695✔
19
    IndividualInterpolationConfig<float>? individualConfigX,
19,695✔
20
    IndividualInterpolationConfig<float>? individualConfigY,
19,695✔
21
    IndividualInterpolationConfig<float>? individualConfigZ)
19,695✔
22
    : ISeparateVector3Keyframes<TKeyframe>
23
    where TKeyframe : IKeyframe<float> {
24
  public SeparateVector3Keyframes(
25
      ISharedInterpolationConfig sharedConfig,
26
      IKeyframeInterpolator<TKeyframe, float> interpolator,
27
      IndividualInterpolationConfig<float>? individualConfig = null)
28
      : this(sharedConfig,
2✔
29
             interpolator,
2✔
30
             individualConfig,
2✔
31
             individualConfig,
2✔
32
             individualConfig) { }
6✔
33

34
  public IReadOnlyList<IInterpolatableKeyframes<TKeyframe, float>> Axes { get; }
501,648✔
35
    = [
19,695✔
36
        new InterpolatedKeyframes<TKeyframe, float>(
19,695✔
37
            sharedConfig,
19,695✔
38
            interpolator,
19,695✔
39
            individualConfigX),
19,695✔
40
        new InterpolatedKeyframes<TKeyframe, float>(
19,695✔
41
            sharedConfig,
19,695✔
42
            interpolator,
19,695✔
43
            individualConfigY),
19,695✔
44
        new InterpolatedKeyframes<TKeyframe, float>(
19,695✔
45
            sharedConfig,
19,695✔
46
            interpolator,
19,695✔
47
            individualConfigZ),
19,695✔
48
    ];
19,695✔
49

50
  public bool TryGetAtFrame(float frame, out Vector3 value) {
20✔
51
    value = default;
20✔
52

53
    if (!this.Axes[0]
20!
54
             .TryGetAtFrameOrDefault(frame, individualConfigX, out var x)) {
20✔
55
      return false;
×
56
    }
57

58
    if (!this.Axes[1]
20!
59
             .TryGetAtFrameOrDefault(frame, individualConfigY, out var y)) {
20✔
60
      return false;
×
61
    }
62

63
    if (!this.Axes[2]
20!
64
             .TryGetAtFrameOrDefault(frame, individualConfigZ, out var z)) {
20✔
65
      return false;
×
66
    }
67

68
    value = new Vector3(x, y, z);
20✔
69
    return true;
20✔
70
  }
20✔
71

72
  public void GetAllFrames(Span<Vector3> dst) {
11,980✔
73
    Span<float> x = stackalloc float[dst.Length];
11,980✔
74
    Span<float> y = stackalloc float[dst.Length];
11,980✔
75
    Span<float> z = stackalloc float[dst.Length];
11,980✔
76

77
    this.Axes[0].GetAllFrames(x);
11,980✔
78
    this.Axes[1].GetAllFrames(y);
11,980✔
79
    this.Axes[2].GetAllFrames(z);
11,980✔
80

81
    for (var i = 0; i < dst.Length; ++i) {
1,967,531✔
82
      dst[i] = new Vector3(x[i], y[i], z[i]);
647,857✔
83
    }
647,857✔
84
  }
11,980✔
85

86
  public bool TryGetSimpleKeyframes(
87
      out IReadOnlyList<(float frame, Vector3 value)> keyframes,
88
      out IReadOnlyList<(Vector3 tangentIn, Vector3 tangentOut)>?
89
          tangentKeyframes) {
17,065✔
90
    var xAxis = this.Axes[0];
17,065✔
91
    var yAxis = this.Axes[1];
17,065✔
92
    var zAxis = this.Axes[2];
17,065✔
93

94
    if (!xAxis.HasAnyData && !yAxis.HasAnyData && !zAxis.HasAnyData) {
17,065!
NEW
95
      keyframes = [];
×
UNCOV
96
      tangentKeyframes = null;
×
NEW
97
      return true;
×
98
    }
99

100
    Span<(IInterpolatableKeyframes<TKeyframe, float> keyframes,
17,065✔
101
        IInterpolatableKeyframes<KeyframeWithTangents<float>, float>? keyframesWithTangents,
17,065✔
102
        IndividualInterpolationConfig<float>? config)> axes = [
17,065✔
103
        (xAxis,
17,065✔
104
         xAxis as IInterpolatableKeyframes<KeyframeWithTangents<float>, float>,
17,065✔
105
         individualConfigX),
17,065✔
106
        (yAxis,
17,065✔
107
         yAxis as IInterpolatableKeyframes<KeyframeWithTangents<float>, float>,
17,065✔
108
         individualConfigY),
17,065✔
109
        (zAxis,
17,065✔
110
         zAxis as IInterpolatableKeyframes<KeyframeWithTangents<float>, float>,
17,065✔
111
         individualConfigZ),
17,065✔
112
    ];
17,065✔
113

114
    if (axes.Any(a => !a.keyframes.HasAnyData &&
68,260!
115
                      !(a.config?.DefaultValue?.Try(out _) ?? false))) {
68,260✔
UNCOV
116
      keyframes = null!;
×
UNCOV
117
      tangentKeyframes = null;
×
UNCOV
118
      return false;
×
119
    }
120

121
    var unionKeyframes
17,065✔
122
        = xAxis.Definitions
17,065✔
123
               .Concat(yAxis.Definitions)
17,065✔
124
               .Concat(zAxis.Definitions)
17,065✔
125
               .Select(keyframe => keyframe.Frame)
360,003✔
126
               .Distinct()
17,065✔
127
               .Order()
17,065✔
128
               .ToArray();
17,065✔
129

130
    var unionKeyframeCount = unionKeyframes.Length;
17,065✔
131

132
    {
17,065✔
133
      var mutableKeyframes = new (float, Vector3)[unionKeyframeCount];
17,065✔
134
      for (var k = 0; k < unionKeyframeCount; ++k) {
485,510✔
135
        var keyframe = unionKeyframes[k];
150,460✔
136
        var value = new Vector3();
150,460✔
137

138
        for (var i = 0; i < axes.Length; ++i) {
1,655,060✔
139
          var axis = axes[i];
451,380✔
140
          Asserts.True(
451,380✔
141
              axis.keyframes.TryGetAtFrameOrDefault(keyframe,
451,380✔
142
                                                    axis.config,
451,380✔
143
                                                    out var axisValue));
451,380✔
144
          value[i] = axisValue;
451,380✔
145
        }
451,380✔
146

147
        mutableKeyframes[k] = (keyframe, value);
150,460✔
148
      }
150,460✔
149

150
      keyframes = mutableKeyframes;
17,065✔
151
    }
17,065✔
152

153
    if (axes.Any(a => a.keyframesWithTangents == null)) {
66,282✔
154
      tangentKeyframes = null;
1,978✔
155
    } else {
17,065✔
156
      var mutableTangentKeyframes = new (Vector3, Vector3)[unionKeyframeCount];
15,087✔
157

158
      for (var k = 0; k < unionKeyframeCount; ++k) {
297,062✔
159
        var keyframe = unionKeyframes[k];
96,948✔
160

161
        var tangentIn = new Vector3();
96,948✔
162
        var tangentOut = new Vector3();
96,948✔
163

164
        for (var i = 0; i < axes.Length; ++i) {
976,079✔
165
          var axis = axes[i];
268,713✔
166
          if (!HermiteInterpolationUtil.TryGetTangent(
268,713✔
167
                  axis.keyframesWithTangents!,
268,713✔
168
                  keyframe,
268,713✔
169
                  out var axisTangentIn,
268,713✔
170
                  out var axisTangentOut)) {
280,691✔
171
            tangentKeyframes = null;
11,978✔
172
            return false;
11,978✔
173
          }
174

175
          tangentIn[i] = axisTangentIn;
256,735✔
176
          tangentOut[i] = axisTangentOut;
256,735✔
177
        }
256,735✔
178

179
        mutableTangentKeyframes[k] = (tangentIn, tangentOut);
84,970✔
180
      }
84,970✔
181

182
      tangentKeyframes = mutableTangentKeyframes;
3,109✔
183
    }
3,109✔
184

185
    return true;
5,087✔
186
  }
17,065✔
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc