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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Numerics;

namespace XFEEDToolBox.Core.Galaxy;

/// <summary>
/// Original3ACA010 prepared descriptor and3AFBD80 consumer. Inputs must be
/// supplied by their actual current sources: constructor radius50 is not a
/// substitute for the radius provider's per-frame value. Native5A8CD0 embeds
/// Camera at frame20: frame40/50 are its forward/eye vectors; the ellipsoid
/// uses the orbit camera's independent focus from3A26260.
/// </summary>
public readonly record struct GalaxyOriginalFrameFade
{
    private readonly Vector3 offset, planeOrigin, planeScale, ellipsoidOrigin, ellipsoidScale;
    private readonly float minimum, innerRadius, outerRadius;
    public bool EllipsoidEnabled { get; }
    public float Transition => minimum;
    public float InnerRadius => innerRadius;
    public float OuterRadius => outerRadius;
    public Vector3 EllipsoidOrigin => ellipsoidOrigin;
    public Vector3 EllipsoidScale => ellipsoidScale;

    // Original3AF5D70 uses this value both as an endpoint and as the upper
    // clamp of a decreasing transition. It is not the ellipsoid-enable limit.
    public const float TransitionUpperLimit = 1.0099999904632568f;
    public const float NearFadeStart = 1.5f; //3ACA010: float[50CB470] / float[4E328D0] =3/2.
    public const float NearFadeEnd = 3;
    public const float FarFadeStart = 600;
    public const float FarFadeEnd = 700;

    private GalaxyOriginalFrameFade(Vector3 offset,Vector3 planeOrigin,Vector3 planeScale,
        Vector3 ellipsoidOrigin,float radius,float t)
    {
        this.offset=offset;this.planeOrigin=planeOrigin;this.planeScale=planeScale;this.ellipsoidOrigin=ellipsoidOrigin;
        minimum=t;EllipsoidEnabled=t<=1;
        // Exact source vector(1,8,1) interpolated towards(1,1,1).
        ellipsoidScale=new(1,(1-t)*8+t,1);
        const float third=.3333333432674408f;
        innerRadius=radius*((1-third)+t*third);
        outerRadius=radius*((1-third)+t*third+.10000000149011612f);
    }

    /// <summary>Missing runtime inputs remain unavailable; no guessed defaults.</summary>
    public static bool TryCreate(Vector3 offset,Vector3 planeOrigin,Vector3 planeScale,
        Vector3 ellipsoidOrigin,float? radius,float? t,out GalaxyOriginalFrameFade fade)
    {
        fade=default;
        if(!Finite(offset)||!Finite(planeOrigin)||!Finite(planeScale)||!Finite(ellipsoidOrigin)||
           radius is not {} r||!float.IsFinite(r)||r<0||t is not {} value||!float.IsFinite(value))return false;
        var candidate=new GalaxyOriginalFrameFade(offset,planeOrigin,planeScale,ellipsoidOrigin,r,value);
        if(!float.IsFinite(candidate.innerRadius)||!float.IsFinite(candidate.outerRadius)||
           candidate.outerRadius<candidate.innerRadius)return false;
        fade=candidate;return true;
    }

    /// <summary>
    /// Exact3A26260 call binding: zero offset, frame50 eye, frame40 depth
    /// vector, and the orbit camera's independent focus. All positions must
    /// share one coordinate frame. Unknown source fields remain unavailable;
    /// this does not infer frame40 from an unrelated camera or replace the
    /// current smoothed transition with its distance-derived target.
    /// </summary>
    public static bool TryCreateFromFrame(Vector3? frame40,Vector3? frame50,Vector3? focus,
        float? rendererRadius,float? currentTransition,out GalaxyOriginalFrameFade fade)
    {
        fade=default;
        if(frame40 is not{} direction||frame50 is not{} eye||focus is not{} centre||
           !Finite(direction)||direction.LengthSquared()<=0)return false;
        return TryCreate(Vector3.Zero,eye,direction,centre,rendererRadius,currentTransition,out fade);
    }

    /// <summary>
    /// Constructs the recovered ordinary frame from the tool's current actual
    /// camera. rendererRadius is the dynamically published renderer280 value
    /// (the ordinary catalogue descriptor's InnerRadius), never its sparse
    /// OuterRadius or QueryFar. currentTransition must be the known smoothed
    /// input state; target-only or missing runtime inputs are not substituted.
    /// Coordinates are evaluated in the camera's own relative world frame.
    /// </summary>
    public static bool TryCreateForCamera(GalaxyCamera? camera,float? rendererRadius,float? currentTransition,
        out GalaxyOriginalFrameFade fade)
    {
        fade=default;if(camera is null)return false;
        var forward=camera.Forward;var eye=camera.Eye;var focus=camera.Focus;
        return TryCreateFromFrame(new((float)forward.X,(float)forward.Y,(float)forward.Z),
            new((float)eye.X,(float)eye.Y,(float)eye.Z),new((float)focus.X,(float)focus.Y,(float)focus.Z),
            rendererRadius,currentTransition,out fade);
    }

    /// <summary>
    /// Original3AF5D70 target only. A mode is needed above the threshold;
    /// below it both branches have the same target. The Settings threshold
    /// is explicit, and no constructor50/query radius is substituted for it.
    /// Verified zero is valid: both comparisons fail and the mode endpoint
    /// is returned without dividing by the threshold.
    /// </summary>
    public static bool TryTargetTransition(float distance,float? settingsThreshold,int? originalViewMode,out float target)
    {
        target=default;
        if(!float.IsFinite(distance)||distance<0||settingsThreshold is not{} threshold||
           !float.IsFinite(threshold)||threshold<0)return false;
        if(distance<threshold*.25f){target=0;return true;}
        if(distance<threshold){target=(distance-threshold*.25f)/(threshold*.75f);return true;}
        if(originalViewMode is not{} mode)return false;
        target=mode==0?TransitionUpperLimit:1;return true;
    }

    /// <summary>
    /// Original3AF5D70 state update. inputFrameValue is the actual input-event
    /// float, not an inferred time unit. A decreasing target1 snaps to1;
    /// other paths interpolate by frameValue*3 with directional clamps.
    /// </summary>
    public static bool TryAdvanceTransition(float? current,float? target,float? inputFrameValue,out float transition)
    {
        transition=default;
        if(current is not{} value||target is not{} destination||inputFrameValue is not{} frame||
           !float.IsFinite(value)||value<0||value>TransitionUpperLimit||
           !float.IsFinite(destination)||destination<0||destination>TransitionUpperLimit||
           !float.IsFinite(frame)||frame<0)return false;
        if(value==destination){transition=value;return true;}
        var increasing=value<destination;
        if(destination==1&&!increasing){transition=1;return true;}
        var next=(destination-value)*frame*3+value;
        transition=increasing?Math.Clamp(next,0,destination):Math.Clamp(next,destination,TransitionUpperLimit);
        return float.IsFinite(transition);
    }

    /// <summary>
    /// Territory's original call sets both flags true. Other consumers can
    /// independently request the original minimum floor or disable far fade.
    /// RGB is untouched; the returned value multiplies prepared source alpha.
    /// </summary>
    public float Alpha(Vector3 position,bool bypassMinimum=true,bool farFade=true)
    {
        if(!Finite(position))throw new ArgumentOutOfRangeException(nameof(position));
        var alpha=1f;
        if(EllipsoidEnabled)
        {
            var delta=(position-ellipsoidOrigin)*ellipsoidScale;
            var squared=delta.X*delta.X+delta.Y*delta.Y+delta.Z*delta.Z;
            if(squared>outerRadius*outerRadius)alpha=0;
            else if(squared>innerRadius*innerRadius)alpha=1-(MathF.Sqrt(squared)-innerRadius)/(outerRadius-innerRadius);
            if(!bypassMinimum&&minimum>=.05000000074505806f&&alpha<=minimum)alpha=minimum;
        }
        if(alpha<=0)return alpha;
        var deltaPlane=(offset+position-planeOrigin)*planeScale;
        var depth=deltaPlane.X+deltaPlane.Y+deltaPlane.Z;
        if(depth<0)return 0;
        if(depth<NearFadeEnd)return depth>NearFadeStart?alpha*((depth-NearFadeStart)/(NearFadeEnd-NearFadeStart)):0;
        if(!farFade||depth<=FarFadeStart)return alpha;
        return depth<FarFadeEnd?alpha*((FarFadeEnd-depth)/(FarFadeEnd-FarFadeStart)):0;
    }

    private static bool Finite(Vector3 value)=>float.IsFinite(value.X)&&float.IsFinite(value.Y)&&float.IsFinite(value.Z);
}