174 lines
5.9 KiB
C#
174 lines
5.9 KiB
C#
using AcDream.Core.Rendering;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.Rendering;
|
|
|
|
public sealed class TranslucencyFadeManagerTests
|
|
{
|
|
[Fact]
|
|
public void StartPartFade_InstantEpsilon_CommitsEndImmediately()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f,
|
|
time: TranslucencyFadeManager.TranslucencyInstantEpsilon);
|
|
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float value));
|
|
Assert.Equal(1f, value);
|
|
|
|
// No ramp survives — advancing further changes nothing.
|
|
mgr.AdvanceAll(10f);
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float after));
|
|
Assert.Equal(1f, after);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartPartFade_ZeroTime_IsTreatedAsInstant()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 5, partIndex: 2, start: 0f, end: 0.5f, time: 0f);
|
|
|
|
Assert.True(mgr.TryGetCurrentValue(5, 2, out float value));
|
|
Assert.Equal(0.5f, value);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartPartFade_RealDuration_ImmediatelyReadableAsStart()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0.2f, end: 0.8f, time: 1f);
|
|
|
|
// Before any AdvanceAll — the ramp's t=0 value must already be readable
|
|
// (FPHook's first Execute call reports value=start on the same frame).
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float value));
|
|
Assert.Equal(0.2f, value);
|
|
}
|
|
|
|
[Fact]
|
|
public void AdvanceAll_LinearInterpolation_MidpointIsExact()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f, time: 1f);
|
|
|
|
mgr.AdvanceAll(0.5f);
|
|
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float value));
|
|
Assert.Equal(0.5f, value, 5);
|
|
}
|
|
|
|
[Fact]
|
|
public void AdvanceAll_AsymmetricRange_LinearAtQuarterDuration()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0.2f, end: 1.0f, time: 4f);
|
|
|
|
mgr.AdvanceAll(1f); // t = 0.25
|
|
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float value));
|
|
Assert.Equal(0.2f + (1.0f - 0.2f) * 0.25f, value, 5);
|
|
}
|
|
|
|
[Fact]
|
|
public void AdvanceAll_Overshoot_CommitsExactEndValue()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f, time: 0.267f);
|
|
|
|
mgr.AdvanceAll(10f); // massive overshoot past duration
|
|
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float value));
|
|
Assert.Equal(1f, value); // bitwise-exact, not approximately-equal
|
|
}
|
|
|
|
[Fact]
|
|
public void AdvanceAll_PastCompletion_IsIdempotent()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f, time: 0.1f);
|
|
|
|
mgr.AdvanceAll(1f);
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float first));
|
|
|
|
mgr.AdvanceAll(1f); // ramp already finished — a second advance must not change anything
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float second));
|
|
|
|
Assert.Equal(first, second);
|
|
Assert.Equal(1f, second);
|
|
}
|
|
|
|
[Fact]
|
|
public void ClearEntity_RemovesActiveAndCommittedState()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f, time: 1f);
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out _));
|
|
|
|
mgr.ClearEntity(1);
|
|
|
|
Assert.False(mgr.TryGetCurrentValue(1, 0, out _));
|
|
mgr.AdvanceAll(1f); // must not throw even though the entity is gone
|
|
Assert.False(mgr.TryGetCurrentValue(1, 0, out _));
|
|
}
|
|
|
|
[Fact]
|
|
public void StartPartFade_SecondCallReplacesFirst()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f, time: 10f);
|
|
mgr.AdvanceAll(1f); // 10% into the first (abandoned) ramp
|
|
|
|
// Restart with a fresh, shorter ramp — the old target must be abandoned.
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0.9f, end: 0f, time: 1f);
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float atRestart));
|
|
Assert.Equal(0.9f, atRestart);
|
|
|
|
mgr.AdvanceAll(1f); // finishes the SECOND ramp, not the first
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float value));
|
|
Assert.Equal(0f, value);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGetCurrentValue_UnknownPart_ReturnsFalse()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
Assert.False(mgr.TryGetCurrentValue(entityId: 999, partIndex: 0, out float value));
|
|
Assert.Equal(0f, value);
|
|
}
|
|
|
|
[Fact]
|
|
public void MultiplePartsOnSameEntity_AdvanceIndependently()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
mgr.StartPartFade(entityId: 1, partIndex: 0, start: 0f, end: 1f, time: 1f);
|
|
mgr.StartPartFade(entityId: 1, partIndex: 1, start: 0f, end: 1f, time: 2f);
|
|
|
|
mgr.AdvanceAll(1f);
|
|
|
|
Assert.True(mgr.TryGetCurrentValue(1, 0, out float part0));
|
|
Assert.True(mgr.TryGetCurrentValue(1, 1, out float part1));
|
|
Assert.Equal(1f, part0); // part 0's 1s ramp is done
|
|
Assert.Equal(0.5f, part1, 5); // part 1's 2s ramp is halfway
|
|
}
|
|
|
|
[Fact]
|
|
public void Revision_AdvancesOnlyWhenCommittedCasterOpacityChanges()
|
|
{
|
|
var mgr = new TranslucencyFadeManager();
|
|
ulong initial = mgr.Revision;
|
|
|
|
mgr.StartPartFade(1, 0, start: 0f, end: 1f, time: 1f);
|
|
ulong started = mgr.Revision;
|
|
Assert.True(started > initial);
|
|
|
|
mgr.AdvanceAll(0f);
|
|
Assert.Equal(started, mgr.Revision);
|
|
mgr.AdvanceAll(0.5f);
|
|
Assert.True(mgr.Revision > started);
|
|
|
|
ulong advanced = mgr.Revision;
|
|
mgr.ClearEntity(999);
|
|
Assert.Equal(advanced, mgr.Revision);
|
|
mgr.ClearEntity(1);
|
|
Assert.True(mgr.Revision > advanced);
|
|
}
|
|
}
|