using System.Buffers.Binary;
namespace XFEEDToolBox.Core.Rendering;
/// <summary>DX10 DDS cube exported from an original game shader resource; no synthetic image generation.</summary>
public sealed record GameSkyboxCube(int Size,int Format,int RowPitch,byte[][] Faces)
{
public static GameSkyboxCube Read(string path)
{
var info=new FileInfo(path);if(info.Length is <148 or >128*1024*1024)throw new InvalidDataException("游戏天空立方体大小无效。");
return Parse(File.ReadAllBytes(path));
}
public static GameSkyboxCube Parse(ReadOnlySpan<byte> bytes)
{
static int U(ReadOnlySpan<byte> b,int at)=>BinaryPrimitives.ReadInt32LittleEndian(b.Slice(at,4));
if(bytes.Length<148||!bytes[..4].SequenceEqual("DDS "u8)||U(bytes,4)!=124||U(bytes,76)!=32||!bytes.Slice(84,4).SequenceEqual("DX10"u8))throw new InvalidDataException("游戏天空立方体的 DDS 头无效。");
var size=U(bytes,12);var format=U(bytes,128);
if(size<16||size>2048||size!=U(bytes,16)||U(bytes,28)>1||U(bytes,132)!=3||(U(bytes,136)&4)==0||U(bytes,140)!=1)throw new InvalidDataException("游戏天空资源不是受支持的完整立方体。");
var block=format is 71 or 72 or 74 or 75 or 77 or 78 or 80 or 81 or 83 or 84 or 95 or 96 or 98 or 99;
var stride=format switch{2=>16,10=>8,28 or 29 or 26 or 67 or 87 or 91=>4,71 or 72 or 80 or 81=>8,74 or 75 or 77 or 78 or 83 or 84 or 95 or 96 or 98 or 99=>16,_=>throw new InvalidDataException("游戏天空立方体的纹理格式尚不支持。")};
var row=(block?(size+3)/4:size)*stride;var faceBytes=row*(block?(size+3)/4:size);
if(bytes.Length!=148+faceBytes*6)throw new InvalidDataException("游戏天空立方体的六个面不完整。");
var faces=new byte[6][];for(var i=0;i<6;i++)faces[i]=bytes.Slice(148+i*faceBytes,faceBytes).ToArray();
return new(size,format,row,faces);
}
}
using System.Buffers.Binary;
namespace XFEEDToolBox.Core.Rendering;
/// <summary>DX10 DDS cube exported from an original game shader resource; no synthetic image generation.</summary>
public sealed record GameSkyboxCube(int Size,int Format,int RowPitch,byte[][] Faces)
{
public static GameSkyboxCube Read(string path)
{
var info=new FileInfo(path);if(info.Length is <148 or >128*1024*1024)throw new InvalidDataException("游戏天空立方体大小无效。");
return Parse(File.ReadAllBytes(path));
}
public static GameSkyboxCube Parse(ReadOnlySpan<byte> bytes)
{
static int U(ReadOnlySpan<byte> b,int at)=>BinaryPrimitives.ReadInt32LittleEndian(b.Slice(at,4));
if(bytes.Length<148||!bytes[..4].SequenceEqual("DDS "u8)||U(bytes,4)!=124||U(bytes,76)!=32||!bytes.Slice(84,4).SequenceEqual("DX10"u8))throw new InvalidDataException("游戏天空立方体的 DDS 头无效。");
var size=U(bytes,12);var format=U(bytes,128);
if(size<16||size>2048||size!=U(bytes,16)||U(bytes,28)>1||U(bytes,132)!=3||(U(bytes,136)&4)==0||U(bytes,140)!=1)throw new InvalidDataException("游戏天空资源不是受支持的完整立方体。");
var block=format is 71 or 72 or 74 or 75 or 77 or 78 or 80 or 81 or 83 or 84 or 95 or 96 or 98 or 99;
var stride=format switch{2=>16,10=>8,28 or 29 or 26 or 67 or 87 or 91=>4,71 or 72 or 80 or 81=>8,74 or 75 or 77 or 78 or 83 or 84 or 95 or 96 or 98 or 99=>16,_=>throw new InvalidDataException("游戏天空立方体的纹理格式尚不支持。")};
var row=(block?(size+3)/4:size)*stride;var faceBytes=row*(block?(size+3)/4:size);
if(bytes.Length!=148+faceBytes*6)throw new InvalidDataException("游戏天空立方体的六个面不完整。");
var faces=new byte[6][];for(var i=0;i<6;i++)faces[i]=bytes.Slice(148+i*faceBytes,faceBytes).ToArray();
return new(size,format,row,faces);
}
}