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