158 lines
3.1 KiB
C#
158 lines
3.1 KiB
C#
|
namespace Fusion.Addons.KCC
|
||
|
{
|
||
|
using System;
|
||
|
|
||
|
public sealed class SmoothItem<T>
|
||
|
{
|
||
|
public int Frame;
|
||
|
public double Size;
|
||
|
public T Value;
|
||
|
}
|
||
|
|
||
|
public abstract class SmoothValue<T>
|
||
|
{
|
||
|
// PUBLIC MEMBERS
|
||
|
|
||
|
public SmoothItem<T>[] Items => _items;
|
||
|
|
||
|
// PRIVATE MEMBERS
|
||
|
|
||
|
private SmoothItem<T>[] _items;
|
||
|
private int _index;
|
||
|
|
||
|
// CONSTRUCTORS
|
||
|
|
||
|
public SmoothValue(int capacity)
|
||
|
{
|
||
|
_items = new SmoothItem<T>[capacity];
|
||
|
|
||
|
for (int i = 0; i < capacity; ++i)
|
||
|
{
|
||
|
_items[i] = new SmoothItem<T>();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// PUBLIC METHODS
|
||
|
|
||
|
public void AddValue(int frame, double size, T value)
|
||
|
{
|
||
|
if (size <= 0.0)
|
||
|
throw new ArgumentException(nameof(size));
|
||
|
|
||
|
SmoothItem<T> item = _items[_index];
|
||
|
if (item.Frame == frame)
|
||
|
{
|
||
|
item.Size = size;
|
||
|
item.Value = value;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_index = (_index + 1) % _items.Length;
|
||
|
|
||
|
item = _items[_index];
|
||
|
item.Frame = frame;
|
||
|
item.Size = size;
|
||
|
item.Value = value;
|
||
|
}
|
||
|
|
||
|
public void ClearValues()
|
||
|
{
|
||
|
SmoothItem<T> smoothItem;
|
||
|
|
||
|
for (int i = 0, count = _items.Length; i < count; ++i)
|
||
|
{
|
||
|
smoothItem = _items[i];
|
||
|
smoothItem.Frame = default;
|
||
|
smoothItem.Size = default;
|
||
|
smoothItem.Value = GetDefaultValue();
|
||
|
}
|
||
|
|
||
|
_index = default;
|
||
|
}
|
||
|
|
||
|
public T CalculateSmoothValue(double window, double size)
|
||
|
{
|
||
|
return CalculateSmoothValue(window, size, out int frames);
|
||
|
}
|
||
|
|
||
|
public T CalculateSmoothValue(double window, double size, out int frames)
|
||
|
{
|
||
|
SmoothItem<T> item;
|
||
|
|
||
|
frames = default;
|
||
|
|
||
|
if (window <= 0.0f)
|
||
|
{
|
||
|
item = _items[_index];
|
||
|
if (item.Frame == default)
|
||
|
return default;
|
||
|
|
||
|
frames = 1;
|
||
|
return item.Value;
|
||
|
}
|
||
|
|
||
|
double remainingWindow = window;
|
||
|
T accumulatedValue = GetDefaultValue();
|
||
|
|
||
|
for (int i = _index; i >= 0; --i)
|
||
|
{
|
||
|
item = _items[i];
|
||
|
if (item.Frame == default)
|
||
|
continue;
|
||
|
|
||
|
if (remainingWindow <= item.Size)
|
||
|
{
|
||
|
double scale = remainingWindow / item.Size;
|
||
|
|
||
|
accumulatedValue = AccumulateValue(accumulatedValue, item.Value, scale);
|
||
|
|
||
|
++frames;
|
||
|
|
||
|
return GetSmoothValue(accumulatedValue, size / window);
|
||
|
}
|
||
|
|
||
|
remainingWindow -= item.Size;
|
||
|
accumulatedValue = AccumulateValue(accumulatedValue, item.Value, 1.0);
|
||
|
|
||
|
++frames;
|
||
|
}
|
||
|
|
||
|
for (int i = _items.Length - 1; i > _index; --i)
|
||
|
{
|
||
|
item = _items[i];
|
||
|
if (item.Frame == default)
|
||
|
continue;
|
||
|
|
||
|
if (remainingWindow < item.Size)
|
||
|
{
|
||
|
double scale = remainingWindow / item.Size;
|
||
|
|
||
|
accumulatedValue = AccumulateValue(accumulatedValue, item.Value, scale);
|
||
|
|
||
|
++frames;
|
||
|
|
||
|
return GetSmoothValue(accumulatedValue, size / window);
|
||
|
}
|
||
|
|
||
|
remainingWindow -= item.Size;
|
||
|
accumulatedValue = AccumulateValue(accumulatedValue, item.Value, 1.0);
|
||
|
|
||
|
++frames;
|
||
|
}
|
||
|
|
||
|
if (remainingWindow >= window)
|
||
|
return default;
|
||
|
|
||
|
double accumulatedSize = window - remainingWindow;
|
||
|
|
||
|
return GetSmoothValue(accumulatedValue, size / accumulatedSize);
|
||
|
}
|
||
|
|
||
|
// SmoothValue INTERFACE
|
||
|
|
||
|
protected abstract T GetDefaultValue();
|
||
|
protected abstract T AccumulateValue(T accumulatedValue, T value, double scale);
|
||
|
protected abstract T GetSmoothValue(T accumulatedValue, double scale);
|
||
|
}
|
||
|
}
|