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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
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;i<samples;i++)depth+=Density((localStar+towardViewer*(near+(i+.5f)*step))*.5f+new Vector3(.5f))*step;
        return MathF.Exp(-depth*1.8f);
    }
    public static bool Intersect(Vector3 origin,Vector3 direction,out float near,out float far)
    {
        near=float.NegativeInfinity;far=float.PositiveInfinity;
        for(var i=0;i<3;i++)
        {
            var o=i==0?origin.X:i==1?origin.Y:origin.Z;var d=i==0?direction.X:i==1?direction.Y:direction.Z;
            if(Math.Abs(d)<1e-7f){if(Math.Abs(o)>1)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);
    }
}

/// <summary>Original 64³ BC7 volume slices and HDR transfer functions; no screenshots or generated cloud textures.</summary>
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<NebulaReferenceIndex>(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;i<transfer.Length;i++)
        {
            float F(int c)=>BinaryPrimitives.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<entry.Size;z++)
        {
            var slice=decoder.DecodeRaw(bytes.AsSpan(entry.VolumeOffset+z*entry.SlicePitch,entry.SlicePitch).ToArray(),entry.Size,entry.Size,CompressionFormat.Bc7);
            for(var i=0;i<slice.Length;i++){var at=(z*entry.Size*entry.Size+i)*4;var p=slice[i];pixels[at]=p.r;pixels[at+1]=p.g;pixels[at+2]=p.b;pixels[at+3]=p.a;}
        }
        return new(entry.Size,pixels,transfer);
    }
}