msh improvements

This commit is contained in:
bird_egop
2026-05-12 01:19:19 +03:00
parent 09bc0110d0
commit 5fc8ba53b2
7 changed files with 674 additions and 509 deletions
+60 -14
View File
@@ -4,42 +4,88 @@ using NResLib;
namespace ParkanPlayground;
/// <summary>
/// MSH-компонент 0x06: индексный буфер
/// MSH-компонент 0x06: индексный буфер.
/// Используется batch-ами 0x0D через Batch.IndexStart / Batch.IndexCount.
/// Индексы являются ushort и обычно читаются тройками как triangle indices.
/// </summary>
public static class Msh0x06
{
public static List<ushort> ReadComponent(
FileStream mshFs, NResArchive archive)
public const int ElementSize = 2;
public static List<ushort> ReadComponent(FileStream mshFs, NResArchive archive)
{
var entry = archive.Files.FirstOrDefault(x => x.FileType == "06 00 00 00");
if (entry is null)
{
throw new Exception("Archive doesn't contain file (06)");
throw new Exception("Archive doesn't contain index buffer component (0x06)");
}
if (entry.ElementSize != 2)
if (entry.ElementSize != ElementSize)
{
throw new Exception("Index buffer component (0x06) element size is not 2");
}
if (entry.FileLength % entry.ElementSize != 0)
if (entry.FileLength % ElementSize != 0)
{
throw new Exception("Index buffer component (0x06) payload size is not divisible by element size");
throw new Exception("Index buffer component (0x06) payload size is not divisible by 2");
}
var data = new byte[entry.FileLength];
mshFs.Seek(entry.OffsetInFile, SeekOrigin.Begin);
mshFs.ReadExactly(data, 0, data.Length);
var elements = new List<ushort>(entry.FileLength / entry.ElementSize);
for (var i = 0; i < entry.FileLength / entry.ElementSize; i++)
var span = data.AsSpan();
var indices = new List<ushort>(entry.FileLength / ElementSize);
for (var offset = 0; offset < span.Length; offset += ElementSize)
{
elements.Add(
BinaryPrimitives.ReadUInt16LittleEndian(data.AsSpan(i * 2))
);
indices.Add(BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(offset, ElementSize)));
}
return elements;
return indices;
}
}
/// <summary>
/// Возвращает triangle triplets из диапазона индексов.
/// Удобно для обхода batch.IndexStart / batch.IndexCount из 0x0D.
/// </summary>
public static IEnumerable<TriangleIndices> EnumerateTriangles(
IReadOnlyList<ushort> indices,
int indexStart,
int indexCount)
{
if (indexStart < 0)
{
throw new ArgumentOutOfRangeException(nameof(indexStart));
}
if (indexCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(indexCount));
}
if (indexStart + indexCount > indices.Count)
{
throw new ArgumentException("Index range is outside the 0x06 index buffer");
}
for (var i = 0; i + 2 < indexCount; i += 3)
{
yield return new TriangleIndices(
indices[indexStart + i + 0],
indices[indexStart + i + 1],
indices[indexStart + i + 2]);
}
}
/// <summary>Тройка индексов triangle из MSH 0x06.</summary>
/// <param name="A">Первый vertex index внутри batch/base vertex range.</param>
/// <param name="B">Второй vertex index внутри batch/base vertex range.</param>
/// <param name="C">Третий vertex index внутри batch/base vertex range.</param>
public readonly record struct TriangleIndices(
ushort A,
ushort B,
ushort C);
}