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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

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

namespace XFEEDToolBox.Core.Rendering;

/// <summary>Actual ManualExposure CS constants cb0[6].xyzw/[7].x.
/// Explicit inputs belong to the view being rendered; no other camera's
/// histogram or unrelated HDR Write/Read is substituted.</summary>
public readonly record struct GalaxyOriginalManualExposureInputs(float ManualExposureEv,float ToeModifier,float ShoulderModifier,float Offset,float Slope);
public enum GalaxyOriginalExposureState { Uninitialized, DefaultCreated, ManualComputed }
public readonly record struct GalaxyOriginalHistogramResult(float LinearAdaptation,float CompensatedLuminance)
{
    public float Type1EmissiveRescaling=>LinearAdaptation*.125f;
    public float Type2EmissiveRescaling=>CompensatedLuminance*.125f;
    public float[] SixTexels()=>[LinearAdaptation,CompensatedLuminance,0,0,0,0];
}

public static class GalaxyOriginalExposure
{
    // Pinned original 351F8E0 stores EV0; 3523480 publishes the enabled
    // 5E8B997 curve using these precise .data bits (918/910/908/914).
    // These are initial controls for this tool view, never a game runtime snapshot.
    public static readonly GalaxyOriginalManualExposureInputs InitialManualControls=new(0,
        BitConverter.Int32BitsToSingle(0x3F80A3D7),BitConverter.Int32BitsToSingle(0x40133333),5,1);
    //3521DD0 creates HDR_Histogram_Result_Default:format16/R32Float,
    //6x1,24bytes at readonly54C7250, all zero. It is usable only after its
    // creation/binding has actually completed, not as an unknown-source guess.
    public static readonly GalaxyOriginalHistogramResult DefaultHistogram=new(0,0);
    public static bool TryManualExposure(GalaxyOriginalManualExposureInputs input,out GalaxyOriginalHistogramResult result)
    {
        result=default;
        if(!float.IsFinite(input.ManualExposureEv)||!float.IsFinite(input.ToeModifier)||!float.IsFinite(input.ShoulderModifier)||
           !float.IsFinite(input.Offset)||!float.IsFinite(input.Slope))return false;
        // Exact operation chain from cs_AnalyseLuminance_ManualExposure.
        // Preserve invalid/unknown inputs rather than clamping to a fake light.
        var adaptation=1/MathF.Pow(2,input.ManualExposureEv);
        var curve=MathF.Log2(adaptation*8)-input.Offset-3;
        curve=MathF.Log2(MathF.Pow(2,curve*input.Slope)+1);
        var shoulder=input.ShoulderModifier*2;
        curve=shoulder/(curve*.3010299956639812f+shoulder);
        curve=MathF.Pow(2,MathF.Log2(curve)*input.ShoulderModifier);
        curve=input.ToeModifier*1.03f-curve;
        var compensation=MathF.Log2(curve/adaptation)-MathF.Log2(.18f/adaptation);
        compensation=MathF.Pow(2,MathF.Log2(adaptation)-compensation);
        if(!float.IsFinite(adaptation)||adaptation<=0||!float.IsFinite(compensation)||compensation<0)return false;
        result=new(adaptation,compensation);return true;
    }
    public static Vector4[] ManualConstants(GalaxyOriginalManualExposureInputs input)
    {
        if(!TryManualExposure(input,out _))throw new ArgumentOutOfRangeException(nameof(input));
        var constants=new Vector4[8];constants[6]=new(input.ManualExposureEv,input.ToeModifier,input.ShoulderModifier,input.Offset);
        constants[7]=new(input.Slope,0,0,0);return constants;
    }
}