using System.IO.Compression;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text.Json;
using XFEEDToolBox.Core.Models;
namespace XFEEDToolBox.Core.Rendering;
/// The authored GalaxyGlow mesh, its named FGM values and original noise mip chain.
public sealed class GalaxyOriginalCoreResources
{
public IReadOnlyList Positions {get;}
public IReadOnlyList Indices {get;}
public IReadOnlyList MaterialConstants {get;}
public IReadOnlyList NoiseMips {get;}
public ReadOnlyMemory NoisePayload {get;}
public const float WorldScale=40000;
public static Vector3 WorldCentre=>new(50000,40955,50000);
internal GalaxyOriginalCoreResources(JsonElement metadata,byte[] mesh,byte[] noise)
{
static void Verify(byte[] bytes,JsonElement part,int length,string hash)
{
if(bytes.Length!=length||part.GetProperty("payloadBytes").GetInt32()!=length||
part.GetProperty("payloadSha256").GetString()!=hash||Convert.ToHexStringLower(SHA256.HashData(bytes))!=hash)
throw new InvalidDataException("原银河核心资源校验失败。");
}
var meshInfo=metadata.GetProperty("mesh");var texture=metadata.GetProperty("texture");
Verify(mesh,meshInfo,2952,"0a3cefa5719b74a016079198183902a25bffb71ca2af970efc4afdcc198f8250");
Verify(noise,texture,3072,"4ce432549ca60cd1704064588bfe3e1030aef468fe2bc5bfd11ae749288e30e9");
if(meshInfo.GetProperty("vertexCount").GetInt32()!=150||meshInfo.GetProperty("indexCount").GetInt32()!=576||
texture.GetProperty("width").GetInt32()!=16||texture.GetProperty("height").GetInt32()!=16||texture.GetProperty("dxgiFormat").GetInt32()!=71)
throw new InvalidDataException("原银河核心资源布局无效。");
Positions=Array.AsReadOnly(MemoryMarshal.Cast(mesh.AsSpan(0,1800)).ToArray());
Indices=Array.AsReadOnly(MemoryMarshal.Cast(mesh.AsSpan(1800)).ToArray());
MaterialConstants=Array.AsReadOnly(metadata.GetProperty("shaderMaterialConstantVectors").EnumerateArray().Select(a=>
{
var v=a.EnumerateArray().Select(n=>n.GetSingle()).ToArray();return new Vector4(v[0],v[1],v[2],v[3]);
}).ToArray());
NoiseMips=Array.AsReadOnly(JsonSerializer.Deserialize(texture.GetProperty("mips"),ToolboxSettings.JsonOptions)!);
NoisePayload=noise;
if(MaterialConstants.Count!=8||NoiseMips.Count!=5||Indices.Any(i=>i>=Positions.Count)||
MaterialConstants[3]!=new Vector4(50000,40955,50000,20000)||MaterialConstants[4].X!=80000||
NoiseMips[^1].Offset+NoiseMips[^1].Size!=noise.Length)
throw new InvalidDataException("原银河核心材质数据无效。");
}
}
public static class GalaxyOriginalCore
{
private static readonly Lazy reference=new(Read);
public static GalaxyOriginalCoreResources Reference=>reference.Value;
private static GalaxyOriginalCoreResources Read()
{
var assembly=typeof(GalaxyOriginalCore).Assembly;
using var jsonStream=assembly.GetManifestResourceStream("XFEEDToolBox.Core.Rendering.original-galaxy-core.json")!;
using var json=JsonDocument.Parse(jsonStream);
byte[] Payload(string name,int length)
{
using var stream=assembly.GetManifestResourceStream("XFEEDToolBox.Core.Rendering.original-galaxy-core-"+name+".gz")!;
using var gzip=new GZipStream(stream,CompressionMode.Decompress);var bytes=new byte[length];gzip.ReadExactly(bytes);
if(gzip.ReadByte()!=-1)throw new InvalidDataException("原银河核心资源超出范围。");return bytes;
}
return new(json.RootElement,Payload("mesh.bin",2952),Payload("noise.bc1",3072));
}
}