using System.Numerics;
using System.Runtime.InteropServices;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Models;
namespace XFEEDToolBox.Core.Rendering;
[StructLayout(LayoutKind.Sequential)]
public readonly record struct GalaxyOriginalPowerActivityBillboard(Vector4 Position,Vector4 UAxisExtent,Vector4 VAxisExtent,Vector4 Colour);
public static class GalaxyOriginalPowerActivityBillboardGeometry
{
public const int VertexCount=4;
public const float AllocationMultiplier=2.222222328186035f;
public static bool TryCreate(GalaxyNativePowerOuter? source,Coordinates eye,out GalaxyOriginalPowerActivityBillboard billboard)
{
billboard=default;
if(source is not{CentreSystemAddress:>0,CentrePosition:{} centre,Extent:>0 and <=1000000}||!centre.IsValid||!eye.IsValid)return false;
var normal=new Vector3((float)(eye.X-centre.X),(float)(eye.Y-centre.Y),(float)(eye.Z-centre.Z));
var distance=normal.Length();var extent=source.Extent.Value;
if(!float.IsFinite(distance)||distance<=extent)return false;
var allocation=extent*(distance/MathF.Sqrt(distance*distance-extent*extent))*AllocationMultiplier;
if(!float.IsFinite(allocation)||allocation<=0)return false;
normal/=distance;var absolute=Vector3.Abs(normal);Vector3 u;
// Exact3B064F0 largest-axis branches, including tie direction.
if(absolute.Y>absolute.X&&absolute.Z<=absolute.Y)u=new(normal.Y,-normal.X,0);
else if(absolute.X>=absolute.Z&&absolute.Y<=absolute.X)u=new(-normal.Z,0,normal.X);
else u=new(0,normal.Z,-normal.Y);
u=Vector3.Normalize(u);var v=Vector3.Cross(u,normal);
billboard=new(new((float)centre.X,(float)centre.Y,(float)centre.Z,1),new(u,allocation),new(v,allocation),
new(BitConverter.Int32BitsToSingle(0x3CDD2F1B),BitConverter.Int32BitsToSingle(0x3F716873),1,0));
return IsValid(billboard);
}
public static bool IsValid(GalaxyOriginalPowerActivityBillboard value)=>Finite(value.Position)&&Finite(value.UAxisExtent)&&
Finite(value.VAxisExtent)&&Finite(value.Colour)&&value.UAxisExtent.W>0&&value.VAxisExtent.W>0;
private static bool Finite(Vector4 value)=>float.IsFinite(value.X)&&float.IsFinite(value.Y)&&float.IsFinite(value.Z)&&float.IsFinite(value.W);
public static Vector3 Vertex(GalaxyOriginalPowerActivityBillboard value,int vertex)
{
if(!IsValid(value)||vertex is <0 or >=VertexCount)throw new ArgumentOutOfRangeException(nameof(vertex));
var u=((vertex&2)!=0?1:-1)*value.UAxisExtent.W*.5f;var v=((vertex&1)!=0?1:-1)*value.VAxisExtent.W*.5f;
return new Vector3(value.Position.X,value.Position.Y,value.Position.Z)+new Vector3(value.UAxisExtent.X,value.UAxisExtent.Y,value.UAxisExtent.Z)*u+
new Vector3(value.VAxisExtent.X,value.VAxisExtent.Y,value.VAxisExtent.Z)*v;
}
}
using System.Numerics;
using System.Runtime.InteropServices;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Models;
namespace XFEEDToolBox.Core.Rendering;
[StructLayout(LayoutKind.Sequential)]
public readonly record struct GalaxyOriginalPowerActivityBillboard(Vector4 Position,Vector4 UAxisExtent,Vector4 VAxisExtent,Vector4 Colour);
public static class GalaxyOriginalPowerActivityBillboardGeometry
{
public const int VertexCount=4;
public const float AllocationMultiplier=2.222222328186035f;
public static bool TryCreate(GalaxyNativePowerOuter? source,Coordinates eye,out GalaxyOriginalPowerActivityBillboard billboard)
{
billboard=default;
if(source is not{CentreSystemAddress:>0,CentrePosition:{} centre,Extent:>0 and <=1000000}||!centre.IsValid||!eye.IsValid)return false;
var normal=new Vector3((float)(eye.X-centre.X),(float)(eye.Y-centre.Y),(float)(eye.Z-centre.Z));
var distance=normal.Length();var extent=source.Extent.Value;
if(!float.IsFinite(distance)||distance<=extent)return false;
var allocation=extent*(distance/MathF.Sqrt(distance*distance-extent*extent))*AllocationMultiplier;
if(!float.IsFinite(allocation)||allocation<=0)return false;
normal/=distance;var absolute=Vector3.Abs(normal);Vector3 u;
// Exact3B064F0 largest-axis branches, including tie direction.
if(absolute.Y>absolute.X&&absolute.Z<=absolute.Y)u=new(normal.Y,-normal.X,0);
else if(absolute.X>=absolute.Z&&absolute.Y<=absolute.X)u=new(-normal.Z,0,normal.X);
else u=new(0,normal.Z,-normal.Y);
u=Vector3.Normalize(u);var v=Vector3.Cross(u,normal);
billboard=new(new((float)centre.X,(float)centre.Y,(float)centre.Z,1),new(u,allocation),new(v,allocation),
new(BitConverter.Int32BitsToSingle(0x3CDD2F1B),BitConverter.Int32BitsToSingle(0x3F716873),1,0));
return IsValid(billboard);
}
public static bool IsValid(GalaxyOriginalPowerActivityBillboard value)=>Finite(value.Position)&&Finite(value.UAxisExtent)&&
Finite(value.VAxisExtent)&&Finite(value.Colour)&&value.UAxisExtent.W>0&&value.VAxisExtent.W>0;
private static bool Finite(Vector4 value)=>float.IsFinite(value.X)&&float.IsFinite(value.Y)&&float.IsFinite(value.Z)&&float.IsFinite(value.W);
public static Vector3 Vertex(GalaxyOriginalPowerActivityBillboard value,int vertex)
{
if(!IsValid(value)||vertex is <0 or >=VertexCount)throw new ArgumentOutOfRangeException(nameof(vertex));
var u=((vertex&2)!=0?1:-1)*value.UAxisExtent.W*.5f;var v=((vertex&1)!=0?1:-1)*value.VAxisExtent.W*.5f;
return new Vector3(value.Position.X,value.Position.Y,value.Position.Z)+new Vector3(value.UAxisExtent.X,value.UAxisExtent.Y,value.UAxisExtent.Z)*u+
new Vector3(value.VAxisExtent.X,value.VAxisExtent.Y,value.VAxisExtent.Z)*v;
}
}