Skip to content

Commit

Permalink
Add builders for model list
Browse files Browse the repository at this point in the history
  • Loading branch information
IntelOrca committed Mar 22, 2024
1 parent 340dd00 commit 124bf26
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 7 deletions.
190 changes: 190 additions & 0 deletions src/IntelOrca.Biohazard/Room/CvModelList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,47 @@ public CvModelList WithNewBaseOffset(int baseOffset)
bw.Write(Data[(PageCount * 4)..]);
return new CvModelList(baseOffset, ms.ToArray());
}

public Builder ToBuilder()
{
var result = new Builder();
result.BaseOffset = BaseOffset;
result.Pages.AddRange(Pages.ToArray());
return result;
}

public class Builder
{
public int BaseOffset { get; set; }
public List<CvModelListPage> Pages { get; } = new List<CvModelListPage>();

public CvModelList ToCvModelList()
{
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);

var offset = BaseOffset + (Pages.Count * 4);
foreach (var page in Pages)
{
if (page.Data.Length == 0)
{
bw.Write(0);
}
else
{
bw.Write(offset);
offset += page.Data.Length;
}
}

foreach (var page in Pages)
{
bw.Write(page.Data);
}

return new CvModelList(BaseOffset, ms.ToArray());
}
}
}

public readonly struct CvModelListPage
Expand All @@ -95,5 +136,154 @@ public CvModelListPage(ReadOnlyMemory<byte> data)
{
Data = data;
}

public int Count
{
get
{
if (Data.Length == 0)
return 0;

var first4 = MemoryMarshal.Read<uint>(Data.Span);
if ((first4 & 0xFFFFFF) == CvModel.MDL || first4 == CvModel.SKIN || first4 == CvModel.MASK)
{
return 1;
}

var count = 0;
var offset = 0;
int len;
while ((len = MemoryMarshal.Read<int>(Data.Span[offset..])) > 0)
{
offset += len + 4;
count++;
}

return count;
}
}

public ReadOnlyMemory<CvModel> Models
{
get
{
var result = new CvModel[Count];
for (var i = 0; i < result.Length; i++)
{
result[i] = GetModel(i);
}
return result;
}
}

public CvModel GetModel(int index)
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));

var first4 = MemoryMarshal.Read<uint>(Data.Span);
if ((first4 & 0xFFFFFF) == CvModel.MDL || first4 == CvModel.SKIN || first4 == CvModel.MASK)
{
return new CvModel(Data);
}

var count = 0;
var offset = 0;
int len;
while ((len = MemoryMarshal.Read<int>(Data.Span[offset..])) != 0)
{
offset += 4;
if (index == count)
{
return new CvModel(Data.Slice(offset, len));
}
offset += len;
count++;
}

throw new InvalidDataException();
}

public Builder ToBuilder()
{
var result = new Builder();
var count = Count;
for (var i = 0; i < count; i++)
{
result.Models.Add(GetModel(i));
}
return result;
}

public class Builder
{
public List<CvModel> Models { get; } = new List<CvModel>();

public CvModelListPage ToCvModelListPage()
{
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);

if (Models.Count == 0)
{
}
else if (Models.Count == 1)
{
bw.Write(Models[0].Data);
}
else
{
for (var i = 0; i < Models.Count; i++)
{
bw.Write(Models[i].Data.Length);
bw.Write(Models[i].Data);
}
bw.Write(-1);
while ((ms.Length % 64) != 0)
{
bw.Write((byte)0);
}
}

return new CvModelListPage(ms.ToArray());
}
}
}

public readonly struct CvModel
{
public const uint MDL = 0x004C444D;
public const uint SKIN = 0x4E494B53;
public const uint MASK = 0x4B53414D;

public ReadOnlyMemory<byte> Data { get; }

public CvModel(ReadOnlyMemory<byte> data)
{
Data = data;
}

public CvModelKind Kind
{
get
{
var k = MemoryMarshal.Read<uint>(Data.Span);
if ((k & 0xFFFFFF) == MDL)
return CvModelKind.Mdl;
if (k == SKIN)
return CvModelKind.Skin;
if (k == MASK)
return CvModelKind.Mask;
return CvModelKind.Unknown;
}
}
}

public enum CvModelKind
{
Unknown,
Mdl,
Skin,
Mask,
}
}
29 changes: 22 additions & 7 deletions test/IntelOrca.Biohazard.Tests/TestCV.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,31 @@ public void RDT_10C_Motion_Rebuild()
public void RDT_10C_Models_Rebuild()
{
var rdt = GetRdt(14);
var m = rdt.Models;
var newBaseOffset = m.BaseOffset + (4 * 6);
var m2 = m.WithNewBaseOffset(newBaseOffset);
var list = rdt.Models;

Assert.Equal(newBaseOffset, m2.BaseOffset);
Assert.Equal(m.PageCount, m2.PageCount);
for (var i = 0; i < m2.PageCount; i++)
// Test WithNewBaseOffset
{
Assert.Equal(m.Pages[i].Data.Length, m2.Pages[i].Data.Length);
var newBaseOffset = list.BaseOffset + (4 * 6);
var m2 = list.WithNewBaseOffset(newBaseOffset);
Assert.Equal(newBaseOffset, m2.BaseOffset);
Assert.Equal(list.PageCount, m2.PageCount);
for (var i = 0; i < m2.PageCount; i++)
{
Assert.Equal(list.Pages[i].Data.Length, m2.Pages[i].Data.Length);
}
}

// Test page builder
for (var i = 0; i < list.Pages.Length; i++)
{
var page = list.Pages[i];
var rebuilt = page.ToBuilder().ToCvModelListPage();
AssertAndCompareMemory(page.Data, rebuilt.Data);
}

// Test list builder
var rebuiltList = list.ToBuilder().ToCvModelList();
AssertAndCompareMemory(list.Data, rebuiltList.Data);
}

private void AssertRebuild(int index)
Expand Down

0 comments on commit 124bf26

Please sign in to comment.