Optimize prepared asset package v2
This commit is contained in:
parent
d123c4b67c
commit
0dd966f3a0
28 changed files with 1277 additions and 106 deletions
|
|
@ -36,34 +36,63 @@ namespace AcDream.Content.Pak;
|
|||
public static class ObjectMeshDataSerializer {
|
||||
public static void Write(ObjectMeshData data, Stream stream) {
|
||||
using var bw = new BinaryWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true);
|
||||
WriteObjectMeshData(bw, data);
|
||||
WriteObjectMeshData(bw, data, externalTextures: null);
|
||||
}
|
||||
|
||||
public static void WriteExternalTextures(
|
||||
ObjectMeshData data,
|
||||
Stream stream,
|
||||
Func<TextureKey, byte[], ulong> registerTexture) {
|
||||
ArgumentNullException.ThrowIfNull(registerTexture);
|
||||
using var bw = new BinaryWriter(
|
||||
stream,
|
||||
System.Text.Encoding.UTF8,
|
||||
leaveOpen: true);
|
||||
WriteObjectMeshData(bw, data, registerTexture);
|
||||
}
|
||||
|
||||
/// <summary>Deserializes directly over <paramref name="bytes"/> — no defensive copy (PakReader's single-pass read reuses its CRC buffer here).</summary>
|
||||
public static ObjectMeshData Read(byte[] bytes) {
|
||||
using var ms = new MemoryStream(bytes, writable: false);
|
||||
using var br = new BinaryReader(ms, System.Text.Encoding.UTF8, leaveOpen: true);
|
||||
return ReadObjectMeshData(br);
|
||||
return ReadObjectMeshData(br, externalTextures: null);
|
||||
}
|
||||
|
||||
public static ObjectMeshData Read(ReadOnlySpan<byte> bytes) => Read(bytes.ToArray());
|
||||
|
||||
public static ObjectMeshData ReadExternalTextures(
|
||||
byte[] bytes,
|
||||
Func<ulong, byte[]> resolveTexture) {
|
||||
ArgumentNullException.ThrowIfNull(resolveTexture);
|
||||
using var ms = new MemoryStream(bytes, writable: false);
|
||||
using var br = new BinaryReader(
|
||||
ms,
|
||||
System.Text.Encoding.UTF8,
|
||||
leaveOpen: true);
|
||||
return ReadObjectMeshData(br, resolveTexture);
|
||||
}
|
||||
|
||||
// ---- ObjectMeshData -----------------------------------------------------
|
||||
|
||||
private static void WriteObjectMeshData(BinaryWriter w, ObjectMeshData data) {
|
||||
private static void WriteObjectMeshData(
|
||||
BinaryWriter w,
|
||||
ObjectMeshData data,
|
||||
Func<TextureKey, byte[], ulong>? externalTextures) {
|
||||
w.Write(data.ObjectId);
|
||||
w.Write(data.IsSetup);
|
||||
|
||||
WriteVertexArray(w, data.Vertices);
|
||||
|
||||
w.Write(data.Batches.Count);
|
||||
foreach (var batch in data.Batches) WriteMeshBatchData(w, batch);
|
||||
foreach (var batch in data.Batches)
|
||||
WriteMeshBatchData(w, batch, externalTextures);
|
||||
|
||||
w.Write(data.UploadAttempts);
|
||||
|
||||
// EnvCellGeometry: recursive nested block.
|
||||
w.Write(data.EnvCellGeometry is not null);
|
||||
if (data.EnvCellGeometry is not null) WriteObjectMeshData(w, data.EnvCellGeometry);
|
||||
if (data.EnvCellGeometry is not null)
|
||||
WriteObjectMeshData(w, data.EnvCellGeometry, externalTextures);
|
||||
|
||||
w.Write(data.SetupParts.Count);
|
||||
foreach (var (gfxObjId, transform) in data.SetupParts) {
|
||||
|
|
@ -74,7 +103,7 @@ public static class ObjectMeshDataSerializer {
|
|||
w.Write(data.ParticleEmitters.Count);
|
||||
foreach (var emitter in data.ParticleEmitters) WriteStagedEmitter(w, emitter);
|
||||
|
||||
WriteTextureBatches(w, data.TextureBatches);
|
||||
WriteTextureBatches(w, data.TextureBatches, externalTextures);
|
||||
|
||||
WriteBoundingBox(w, data.BoundingBox);
|
||||
WriteVector3(w, data.SortCenter);
|
||||
|
|
@ -86,7 +115,9 @@ public static class ObjectMeshDataSerializer {
|
|||
WriteVector3Array(w, data.EdgeLines);
|
||||
}
|
||||
|
||||
private static ObjectMeshData ReadObjectMeshData(BinaryReader r) {
|
||||
private static ObjectMeshData ReadObjectMeshData(
|
||||
BinaryReader r,
|
||||
Func<ulong, byte[]>? externalTextures) {
|
||||
var data = new ObjectMeshData {
|
||||
ObjectId = r.ReadUInt64(),
|
||||
IsSetup = r.ReadBoolean(),
|
||||
|
|
@ -96,13 +127,16 @@ public static class ObjectMeshDataSerializer {
|
|||
|
||||
int batchCount = r.ReadInt32();
|
||||
var batches = new List<MeshBatchData>(batchCount);
|
||||
for (int i = 0; i < batchCount; i++) batches.Add(ReadMeshBatchData(r));
|
||||
for (int i = 0; i < batchCount; i++)
|
||||
batches.Add(ReadMeshBatchData(r, externalTextures));
|
||||
data.Batches = batches;
|
||||
|
||||
data.UploadAttempts = r.ReadInt32();
|
||||
|
||||
bool hasEnvCellGeometry = r.ReadBoolean();
|
||||
data.EnvCellGeometry = hasEnvCellGeometry ? ReadObjectMeshData(r) : null;
|
||||
data.EnvCellGeometry = hasEnvCellGeometry
|
||||
? ReadObjectMeshData(r, externalTextures)
|
||||
: null;
|
||||
|
||||
int setupPartCount = r.ReadInt32();
|
||||
var setupParts = new List<(ulong GfxObjId, Matrix4x4 Transform)>(setupPartCount);
|
||||
|
|
@ -118,7 +152,7 @@ public static class ObjectMeshDataSerializer {
|
|||
for (int i = 0; i < emitterCount; i++) emitters.Add(ReadStagedEmitter(r));
|
||||
data.ParticleEmitters = emitters;
|
||||
|
||||
data.TextureBatches = ReadTextureBatches(r);
|
||||
data.TextureBatches = ReadTextureBatches(r, externalTextures);
|
||||
|
||||
data.BoundingBox = ReadBoundingBox(r);
|
||||
data.SortCenter = ReadVector3(r);
|
||||
|
|
@ -134,24 +168,37 @@ public static class ObjectMeshDataSerializer {
|
|||
|
||||
// ---- MeshBatchData -------------------------------------------------------
|
||||
|
||||
private static void WriteMeshBatchData(BinaryWriter w, MeshBatchData batch) {
|
||||
private static void WriteMeshBatchData(
|
||||
BinaryWriter w,
|
||||
MeshBatchData batch,
|
||||
Func<TextureKey, byte[], ulong>? externalTextures) {
|
||||
WriteUInt16Array(w, batch.Indices);
|
||||
WriteTextureFormatTuple(w, batch.TextureFormat);
|
||||
WriteTextureKey(w, batch.TextureKey);
|
||||
w.Write(batch.TextureIndex);
|
||||
WriteByteArray(w, batch.TextureData);
|
||||
WriteTexturePayload(
|
||||
w,
|
||||
batch.TextureKey,
|
||||
batch.TextureData,
|
||||
externalTextures);
|
||||
WriteNullableInt32Enum(w, batch.UploadPixelFormat.HasValue, batch.UploadPixelFormat is { } upf ? (int)upf : 0);
|
||||
WriteNullableInt32Enum(w, batch.UploadPixelType.HasValue, batch.UploadPixelType is { } upt ? (int)upt : 0);
|
||||
w.Write((int)batch.CullMode);
|
||||
}
|
||||
|
||||
private static MeshBatchData ReadMeshBatchData(BinaryReader r) {
|
||||
private static MeshBatchData ReadMeshBatchData(
|
||||
BinaryReader r,
|
||||
Func<ulong, byte[]>? externalTextures) {
|
||||
ushort[] indices = ReadUInt16Array(r);
|
||||
(int Width, int Height, TextureFormat Format) format =
|
||||
ReadTextureFormatTuple(r);
|
||||
TextureKey key = ReadTextureKey(r);
|
||||
var batch = new MeshBatchData {
|
||||
Indices = ReadUInt16Array(r),
|
||||
TextureFormat = ReadTextureFormatTuple(r),
|
||||
TextureKey = ReadTextureKey(r),
|
||||
Indices = indices,
|
||||
TextureFormat = format,
|
||||
TextureKey = key,
|
||||
TextureIndex = r.ReadInt32(),
|
||||
TextureData = ReadByteArray(r),
|
||||
TextureData = ReadTexturePayload(r, externalTextures),
|
||||
};
|
||||
batch.UploadPixelFormat = ReadNullableInt32Enum(r, v => (UploadPixelFormat)v);
|
||||
batch.UploadPixelType = ReadNullableInt32Enum(r, v => (UploadPixelType)v);
|
||||
|
|
@ -161,9 +208,12 @@ public static class ObjectMeshDataSerializer {
|
|||
|
||||
// ---- TextureBatchData / TextureBatches dictionary -------------------------
|
||||
|
||||
private static void WriteTextureBatchData(BinaryWriter w, TextureBatchData batch) {
|
||||
private static void WriteTextureBatchData(
|
||||
BinaryWriter w,
|
||||
TextureBatchData batch,
|
||||
Func<TextureKey, byte[], ulong>? externalTextures) {
|
||||
WriteTextureKey(w, batch.Key);
|
||||
WriteByteArray(w, batch.TextureData);
|
||||
WriteTexturePayload(w, batch.Key, batch.TextureData, externalTextures);
|
||||
WriteNullableInt32Enum(w, batch.UploadPixelFormat.HasValue, batch.UploadPixelFormat is { } upf ? (int)upf : 0);
|
||||
WriteNullableInt32Enum(w, batch.UploadPixelType.HasValue, batch.UploadPixelType is { } upt ? (int)upt : 0);
|
||||
WriteUInt16List(w, batch.Indices);
|
||||
|
|
@ -174,10 +224,13 @@ public static class ObjectMeshDataSerializer {
|
|||
w.Write(batch.HasWrappingUVs);
|
||||
}
|
||||
|
||||
private static TextureBatchData ReadTextureBatchData(BinaryReader r) {
|
||||
private static TextureBatchData ReadTextureBatchData(
|
||||
BinaryReader r,
|
||||
Func<ulong, byte[]>? externalTextures) {
|
||||
TextureKey key = ReadTextureKey(r);
|
||||
var batch = new TextureBatchData {
|
||||
Key = ReadTextureKey(r),
|
||||
TextureData = ReadByteArray(r),
|
||||
Key = key,
|
||||
TextureData = ReadTexturePayload(r, externalTextures),
|
||||
};
|
||||
batch.UploadPixelFormat = ReadNullableInt32Enum(r, v => (UploadPixelFormat)v);
|
||||
batch.UploadPixelType = ReadNullableInt32Enum(r, v => (UploadPixelType)v);
|
||||
|
|
@ -198,7 +251,8 @@ public static class ObjectMeshDataSerializer {
|
|||
/// </summary>
|
||||
private static void WriteTextureBatches(
|
||||
BinaryWriter w,
|
||||
Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>> batches) {
|
||||
Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>> batches,
|
||||
Func<TextureKey, byte[], ulong>? externalTextures) {
|
||||
var sortedKeys = batches.Keys
|
||||
.OrderBy(k => k.Width)
|
||||
.ThenBy(k => k.Height)
|
||||
|
|
@ -213,11 +267,14 @@ public static class ObjectMeshDataSerializer {
|
|||
|
||||
var list = batches[key];
|
||||
w.Write(list.Count);
|
||||
foreach (var item in list) WriteTextureBatchData(w, item);
|
||||
foreach (var item in list)
|
||||
WriteTextureBatchData(w, item, externalTextures);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>> ReadTextureBatches(BinaryReader r) {
|
||||
private static Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>> ReadTextureBatches(
|
||||
BinaryReader r,
|
||||
Func<ulong, byte[]>? externalTextures) {
|
||||
int groupCount = r.ReadInt32();
|
||||
var result = new Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>>(groupCount);
|
||||
for (int i = 0; i < groupCount; i++) {
|
||||
|
|
@ -227,13 +284,32 @@ public static class ObjectMeshDataSerializer {
|
|||
|
||||
int listCount = r.ReadInt32();
|
||||
var list = new List<TextureBatchData>(listCount);
|
||||
for (int j = 0; j < listCount; j++) list.Add(ReadTextureBatchData(r));
|
||||
for (int j = 0; j < listCount; j++)
|
||||
list.Add(ReadTextureBatchData(r, externalTextures));
|
||||
|
||||
result[(width, height, format)] = list;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void WriteTexturePayload(
|
||||
BinaryWriter writer,
|
||||
TextureKey key,
|
||||
byte[] bytes,
|
||||
Func<TextureKey, byte[], ulong>? externalTextures) {
|
||||
if (externalTextures is null)
|
||||
WriteByteArray(writer, bytes);
|
||||
else
|
||||
writer.Write(externalTextures(key, bytes));
|
||||
}
|
||||
|
||||
private static byte[] ReadTexturePayload(
|
||||
BinaryReader reader,
|
||||
Func<ulong, byte[]>? externalTextures) =>
|
||||
externalTextures is null
|
||||
? ReadByteArray(reader)
|
||||
: externalTextures(reader.ReadUInt64());
|
||||
|
||||
// ---- StagedEmitter / ParticleEmitter (DBObj) ------------------------------
|
||||
|
||||
private static void WriteStagedEmitter(BinaryWriter w, StagedEmitter emitter) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue