XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFEEDToolBox.Core.Rendering;

public readonly record struct GalaxyOriginalDustLayerFactors(float Alpha,float Size);

/// <summary>Explicit current producer settings, rather than constructor defaults.
/// This does not supply an effective material tint or enable a Dust draw pass.</summary>
public sealed record GalaxyOriginalDustInputs(uint Step,uint Height,IReadOnlyList<GalaxyOriginalDustLayerFactors> Layers,
    float AlphaMultiplier,float SizeMultiplier,float TransitionPerStep,float MinimumDistance);

/// <summary>A completed publication of the cache being rendered. Game-camera
/// completion cannot be substituted for the tool's independently generated cache.</summary>
public readonly record struct GalaxyOriginalDustPublication(int Ordinal,uint PublishedRevision,uint RequestedRevision,float Radius,ulong RecordCount)
{
    public bool Published=>PublishedRevision!=0;
}

public readonly record struct GalaxyOriginalDustLayerFrame(float LowerDistance,float UpperDistance,float TransitionWidth,
    float AlphaMultiplier,float SizeMultiplier,bool HeightMultiplierEnabled);

/// <summary>Actual3A21BC0 record parameters and original Dust VS distance math.
/// Distances retain the source's absolute-coordinate domain.</summary>
public static class GalaxyOriginalDustFrame
{
    public const float CoarseUpperDistance=300000;
    public static bool TryCreate(GalaxyOriginalDustInputs? inputs,IReadOnlyList<GalaxyOriginalDustPublication>? publications,int ordinal,
        out GalaxyOriginalDustLayerFrame frame)
    {
        frame=default;
        static bool Nonnegative(float value)=>float.IsFinite(value)&&value>=0;
        if(inputs is null||inputs.Step==0||inputs.Height==0||inputs.Layers is not{Count:3}||publications is not{Count:3}||ordinal is <0 or >2||
           !Nonnegative(inputs.AlphaMultiplier)||!Nonnegative(inputs.SizeMultiplier)||!Nonnegative(inputs.TransitionPerStep)||!Nonnegative(inputs.MinimumDistance))return false;
        for(var i=0;i<3;i++)
            if(publications[i].Ordinal!=i||!Nonnegative(inputs.Layers[i].Alpha)||!Nonnegative(inputs.Layers[i].Size)||
               publications[i].Published&&!Nonnegative(publications[i].Radius))return false;
        var current=publications[ordinal];if(!current.Published)return false;
        var width=(float)inputs.Step;for(var i=0;i<ordinal;i++)width*=.5f;
        width*=inputs.TransitionPerStep;
        var lower=inputs.MinimumDistance;
        if(ordinal!=1&&ordinal+1<3&&publications[ordinal+1].Published)lower=publications[ordinal+1].Radius-width*.5f;
        var upper=ordinal==0?CoarseUpperDistance:current.Radius+width;
        var alpha=inputs.Layers[ordinal].Alpha*inputs.AlphaMultiplier;
        var size=inputs.Layers[ordinal].Size*inputs.SizeMultiplier;
        if(!float.IsFinite(width)||!float.IsFinite(lower)||!float.IsFinite(upper)||!float.IsFinite(alpha)||!float.IsFinite(size))return false;
        frame=new(lower,upper,width,alpha,size,ordinal==0);return true;
    }

    public static float? DistanceFade(float distance,GalaxyOriginalDustLayerFrame frame)
    {
        if(!float.IsFinite(distance)||distance<0||!float.IsFinite(frame.LowerDistance)||!float.IsFinite(frame.UpperDistance)||
           !float.IsFinite(frame.TransitionWidth)||frame.TransitionWidth<0)return null;
        var denominator=frame.TransitionWidth+.001f;
        return Math.Clamp((distance-frame.LowerDistance)/denominator,0,1)*Math.Clamp((frame.UpperDistance-distance)/denominator,0,1);
    }
}