2024-06-17 18:10:53 +00:00
|
|
|
using DirectXTex;
|
2021-09-27 12:42:46 +00:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
2024-06-17 18:10:53 +00:00
|
|
|
using System.Runtime.InteropServices;
|
2021-09-27 12:42:46 +00:00
|
|
|
using System.Text;
|
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Wabbajack.DTOs.BSA.FileStates;
|
|
|
|
using Wabbajack.DTOs.Texture;
|
|
|
|
|
2024-06-17 18:10:53 +00:00
|
|
|
namespace Wabbajack.Compression.BSA.BA2Archive;
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
public class DX10FileEntryBuilder : IFileBuilder
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
private List<ChunkBuilder> _chunks;
|
|
|
|
private BA2DX10File _state;
|
2024-06-17 18:10:53 +00:00
|
|
|
private uint _headerSize = 0;
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
public uint FileHash => _state.NameHash;
|
|
|
|
public uint DirHash => _state.DirHash;
|
|
|
|
public string FullName => (string) _state.Path;
|
|
|
|
public int Index => _state.Index;
|
|
|
|
|
|
|
|
public void WriteHeader(BinaryWriter bw, CancellationToken token)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
bw.Write(_state.NameHash);
|
|
|
|
bw.Write(Encoding.UTF8.GetBytes(_state.Extension));
|
|
|
|
bw.Write(_state.DirHash);
|
|
|
|
bw.Write(_state.Unk8);
|
|
|
|
bw.Write((byte) _chunks.Count);
|
|
|
|
bw.Write(_state.ChunkHdrLen);
|
|
|
|
bw.Write(_state.Height);
|
|
|
|
bw.Write(_state.Width);
|
|
|
|
bw.Write(_state.NumMips);
|
|
|
|
bw.Write(_state.PixelFormat);
|
2022-12-28 16:21:58 +00:00
|
|
|
bw.Write((byte)_state.IsCubeMap);
|
|
|
|
bw.Write((byte)_state.TileMode);
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
foreach (var chunk in _chunks)
|
|
|
|
chunk.WriteHeader(bw);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async ValueTask WriteData(BinaryWriter wtr, CancellationToken token)
|
|
|
|
{
|
|
|
|
foreach (var chunk in _chunks)
|
|
|
|
await chunk.WriteData(wtr, token);
|
|
|
|
}
|
2024-06-17 18:10:53 +00:00
|
|
|
public uint GetHeaderSize(BA2DX10File state)
|
|
|
|
{
|
|
|
|
if (_headerSize > 0)
|
|
|
|
return _headerSize;
|
|
|
|
|
|
|
|
uint size = 0;
|
|
|
|
size += (uint)Marshal.SizeOf(DirectXTexUtility.DDSHeader.DDSMagic);
|
|
|
|
size += (uint)Marshal.SizeOf<DirectXTexUtility.DDSHeader>();
|
|
|
|
var metadata = DirectXTexUtility.GenerateMetadata(state.Width, state.Height, state.NumMips, (DirectXTexUtility.DXGIFormat)state.PixelFormat, state.IsCubeMap == 1);
|
|
|
|
var pixelFormat = DirectXTexUtility.GetPixelFormat(metadata);
|
|
|
|
var hasDx10Header = DirectXTexUtility.HasDx10Header(pixelFormat);
|
|
|
|
if (hasDx10Header)
|
|
|
|
size += (uint)Marshal.SizeOf<DirectXTexUtility.DX10Header>();
|
|
|
|
|
|
|
|
return _headerSize = size;
|
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
2024-06-17 18:10:53 +00:00
|
|
|
public static async Task<DX10FileEntryBuilder> Create(BA2DX10File state, Stream src, DiskSlabAllocator slab, bool useLz4Compression,
|
2021-10-23 16:51:17 +00:00
|
|
|
CancellationToken token)
|
|
|
|
{
|
|
|
|
var builder = new DX10FileEntryBuilder {_state = state};
|
|
|
|
|
2024-06-17 18:10:53 +00:00
|
|
|
var headerSize = builder.GetHeaderSize(state);
|
2021-10-23 16:51:17 +00:00
|
|
|
new BinaryReader(src).ReadBytes((int) headerSize);
|
|
|
|
|
|
|
|
// This can't be parallel because it all runs off the same base IO stream.
|
|
|
|
builder._chunks = new List<ChunkBuilder>();
|
|
|
|
|
|
|
|
foreach (var chunk in state.Chunks)
|
2024-06-17 18:10:53 +00:00
|
|
|
builder._chunks.Add(await ChunkBuilder.Create(state, chunk, src, slab, useLz4Compression, token));
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
return builder;
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
}
|