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;
}
}
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;
}
}