using System.Buffers.Binary; using System.IO.Compression; using System.Numerics; using System.Text.Json; using BCnEncoder.Decoder; using BCnEncoder.Shared; using XFEEDToolBox.Core.Models; namespace XFEEDToolBox.Core.Rendering; public sealed record NebulaTextureReference(string Name,string ResourceHash,string SourceSha256,int DeflateOffset,int InflatedBytes,int VolumeOffset,int RangeOffset,int Size,int RowPitch,int SlicePitch); public sealed record GalacticNebula(string Name,Coordinates Position,float HalfSize,float[] Rotation,string Template,bool Dark,bool ExactTemplate) { public Quaternion Orientation=>Quaternion.CreateFromYawPitchRoll(Rotation[1],Rotation[0],Rotation[2]); public Vector3 Centre=>new((float)Position.X,(float)Position.Y,(float)Position.Z); } public sealed record NebulaReferenceIndex(string GameSha256,string CatalogSha256,NebulaTextureReference[] Templates,GalacticNebula[] Nebulae); public sealed record NebulaVolume(int Size,byte[] Rgba,Vector4[] Transfer) { public float Density(Vector3 uv) { if(uv.X<0||uv.Y<0||uv.Z<0||uv.X>1||uv.Y>1||uv.Z>1)return 0; var x=Math.Clamp((int)(uv.X*(Size-1)+.5f),0,Size-1);var y=Math.Clamp((int)(uv.Y*(Size-1)+.5f),0,Size-1);var z=Math.Clamp((int)(uv.Z*(Size-1)+.5f),0,Size-1); var alpha=Rgba[((z*Size+y)*Size+x)*4+3]/255f; return alpha*Math.Max(0,Transfer[Math.Clamp((int)(alpha*255),0,255)].W); } public float Transmission(Vector3 localStar,Vector3 towardViewer,float maximumDistance=float.PositiveInfinity) { if(!Intersect(localStar,towardViewer,out var near,out var far)||far<=0)return 1; near=Math.Max(0,near);far=Math.Min(far,maximumDistance);if(far<=near)return 1; const int samples=12;var step=(far-near)/samples;var depth=0f; for(var i=0;i1)return false;continue;} var a=(-1-o)/d;var b=(1-o)/d;if(a>b)(a,b)=(b,a); near=Math.Max(near,a);far=Math.Min(far,b);if(near>=far)return false; } return float.IsFinite(near)&&float.IsFinite(far); } } /// Original 64³ BC7 volume slices and HDR transfer functions; no screenshots or generated cloud textures. public static class EliteNebulae { public static NebulaReferenceIndex Reference {get;}=ReadReference(); private static NebulaReferenceIndex ReadReference() { using var stream=typeof(EliteNebulae).Assembly.GetManifestResourceStream("XFEEDToolBox.Core.Rendering.local-nebula-reference.json")!; return JsonSerializer.Deserialize(stream,ToolboxSettings.JsonOptions)!; } public static NebulaVolume Read(EliteLocalModels resources,string template) { var entry=Reference.Templates.Single(r=>r.Name.Equals(template,StringComparison.OrdinalIgnoreCase)); var raw=resources.ReadDisplayResource(entry.ResourceHash,entry.SourceSha256); if(entry.DeflateOffset<144||entry.DeflateOffset>=raw.Length||entry.InflatedBytes!=361512||!raw.AsSpan(0,4).SequenceEqual("FRES"u8))throw new InvalidDataException("星云资源封装无效。"); using var compressed=new ZLibStream(new MemoryStream(raw,entry.DeflateOffset,raw.Length-entry.DeflateOffset,false),CompressionMode.Decompress); var bytes=new byte[entry.InflatedBytes];compressed.ReadExactly(bytes); if(compressed.ReadByte()!=-1)throw new InvalidDataException("星云资源长度与索引不符。"); return Decode(bytes,entry); } public static NebulaVolume Decode(byte[] bytes,NebulaTextureReference entry) { if(bytes.Length!=entry.InflatedBytes||entry.Size!=64||entry.RowPitch!=256||entry.SlicePitch!=4096||entry.VolumeOffset<1064||entry.RangeOffset<1064|| (long)entry.VolumeOffset+entry.SlicePitch*entry.Size>bytes.Length||(long)entry.RangeOffset+256*16>bytes.Length)throw new InvalidDataException("星云体积纹理越界。"); var transfer=new Vector4[256]; for(var i=0;iBinaryPrimitives.ReadSingleLittleEndian(bytes.AsSpan(entry.RangeOffset+i*16+c*4,4)); var v=new Vector4(F(0),F(1),F(2),F(3)); if(!float.IsFinite(v.X+v.Y+v.Z+v.W)||Math.Abs(v.X)>10000||Math.Abs(v.Y)>10000||Math.Abs(v.Z)>10000||v.W is <0 or >10000)throw new InvalidDataException("星云传递函数无效。"); transfer[i]=v; } var pixels=new byte[entry.Size*entry.Size*entry.Size*4];var decoder=new BcDecoder(); for(var z=0;z