Add mesh reading and conversion support
This commit is contained in:
parent
65dc96c4d6
commit
aa1277a4e1
25 changed files with 2212 additions and 9 deletions
157
LibDgf/Mesh/Db2.cs
Normal file
157
LibDgf/Mesh/Db2.cs
Normal file
|
@ -0,0 +1,157 @@
|
|||
using LibDgf.Ps2.Vif;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Mesh
|
||||
{
|
||||
public class Db2
|
||||
{
|
||||
BinaryReader br;
|
||||
|
||||
public List<Db2Element> Elements { get; set; } = new List<Db2Element>();
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
uint vifStreamLength = br.ReadUInt32();
|
||||
uint version = br.ReadUInt32();
|
||||
if (version != 2) throw new InvalidDataException("DB version is not 2.");
|
||||
uint reserved1 = br.ReadUInt32();
|
||||
uint reserved2 = br.ReadUInt32();
|
||||
//if (reserved1 != 0 || reserved2 != 0)
|
||||
// System.Diagnostics.Debugger.Break();
|
||||
|
||||
Elements.Clear();
|
||||
var startPos = br.BaseStream.Position;
|
||||
var endPos = startPos + vifStreamLength;
|
||||
this.br = br;
|
||||
try
|
||||
{
|
||||
ExpectNop();
|
||||
ExpectNop();
|
||||
ExpectStCycl();
|
||||
ExpectUnpackV4_32();
|
||||
|
||||
while (br.BaseStream.Position < endPos)
|
||||
{
|
||||
Db2Element element = new Db2Element();
|
||||
element.ElementLength = br.ReadInt32();
|
||||
element.Flags = br.ReadUInt32();
|
||||
//if ((element.Flags & 0xFFFFE0E0) != 0)
|
||||
// System.Diagnostics.Debugger.Break();
|
||||
element.TextureIndex = br.ReadInt32();
|
||||
element.Reserved = br.ReadUInt32();
|
||||
//if (element.Reserved != 0)
|
||||
// System.Diagnostics.Debugger.Break();
|
||||
|
||||
int numReglistWords = (int)(element.Flags & 0xf);
|
||||
if (numReglistWords != 0)
|
||||
{
|
||||
element.GsRegs = br.ReadBytes((numReglistWords + 1) * 16);
|
||||
}
|
||||
|
||||
element.GifTagFan = br.ReadBytes(16);
|
||||
element.GifTagStrip = br.ReadBytes(16);
|
||||
|
||||
// Retrieve number of vertices from GIFtag NLOOP
|
||||
int numVertices = element.VertexCount;
|
||||
for (int i = 0; i < numVertices; ++i)
|
||||
{
|
||||
element.Vertices.Add(br.ReadV4_32());
|
||||
}
|
||||
|
||||
ExpectUnpackV3_16((byte)numVertices);
|
||||
for (int i = 0; i < numVertices; ++i)
|
||||
{
|
||||
element.VertexNormals.Add(new Tuple<double, double, double>(
|
||||
Utils.Convert12BitFixedToDouble(br.ReadInt16()),
|
||||
Utils.Convert12BitFixedToDouble(br.ReadInt16()),
|
||||
Utils.Convert12BitFixedToDouble(br.ReadInt16())
|
||||
));
|
||||
}
|
||||
ReadAlign(startPos, 4);
|
||||
|
||||
// Do STs exist if no texture?
|
||||
ExpectUnpackV2_16((byte)numVertices);
|
||||
for (int i = 0; i < numVertices; ++i)
|
||||
{
|
||||
element.STCoordinates.Add(new Tuple<double, double>(
|
||||
Utils.Convert12BitFixedToDouble(br.ReadInt16()),
|
||||
Utils.Convert12BitFixedToDouble(br.ReadInt16())
|
||||
));
|
||||
}
|
||||
ReadAlign(startPos, 16); // Skipping over some NOPs in the process, assume that's what they are
|
||||
|
||||
ExpectMsCnt();
|
||||
|
||||
Elements.Add(element);
|
||||
|
||||
ExpectNop();
|
||||
if (br.BaseStream.Position == endPos - 8)
|
||||
{
|
||||
ExpectNop();
|
||||
ExpectNop();
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectStCycl();
|
||||
ExpectUnpackV4_32();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.br = null;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadAlign(long startPos, int bytes)
|
||||
{
|
||||
var aligned = (br.BaseStream.Position - startPos + bytes - 1) / bytes * bytes;
|
||||
br.BaseStream.Seek(startPos + aligned - br.BaseStream.Position, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
#region Sanity checking functions
|
||||
|
||||
VifCode ExpectNop()
|
||||
{
|
||||
return ExpectVifCode(0x00000000, 0x7f000000);
|
||||
}
|
||||
|
||||
VifCode ExpectStCycl()
|
||||
{
|
||||
return ExpectVifCode(0x01000404, 0x7f00ffff);
|
||||
}
|
||||
|
||||
VifCodeUnpack ExpectUnpackV4_32()
|
||||
{
|
||||
return (VifCodeUnpack)ExpectVifCode(0x6c008000, 0x6f00c000);
|
||||
}
|
||||
|
||||
VifCodeUnpack ExpectUnpackV3_16(byte num)
|
||||
{
|
||||
return (VifCodeUnpack)ExpectVifCode(0x69008000 | ((uint)num << 16), 0x6fffc000);
|
||||
}
|
||||
|
||||
VifCodeUnpack ExpectUnpackV2_16(byte num)
|
||||
{
|
||||
return (VifCodeUnpack)ExpectVifCode(0x65008000 | ((uint)num << 16), 0x6fffc000);
|
||||
}
|
||||
|
||||
VifCode ExpectMsCnt()
|
||||
{
|
||||
return ExpectVifCode(0x17000000, 0x7f000000);
|
||||
}
|
||||
|
||||
VifCode ExpectVifCode(uint value, uint mask)
|
||||
{
|
||||
uint read = br.ReadUInt32();
|
||||
if ((read & mask) != value)
|
||||
throw new InvalidDataException($"VIFcode expectation failed at {br.BaseStream.Position - 4:x8}.");
|
||||
return new VifCode { Value = read };
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
89
LibDgf/Mesh/Db2Element.cs
Normal file
89
LibDgf/Mesh/Db2Element.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
using LibDgf.Ps2.Vif;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Mesh
|
||||
{
|
||||
public class Db2Element
|
||||
{
|
||||
// Size of element in 128-bit words, including header, excluding surrounding VIFcodes
|
||||
public int ElementLength { get; set; }
|
||||
// 0x000f: number of REGLIST words (excluding leading GIFtag)
|
||||
// 0x0010: has texture
|
||||
// 0x00e0: reserved
|
||||
// 0x0100: has vertex color (deprecated, probably)
|
||||
// 0x0e00: GIFtag index - with standard REGLIST primitive: 3 = triangle fan, 4 = triangle strip
|
||||
// 0x1000: disable lighting
|
||||
// 0x80000: textures enabled (only set at runtime)
|
||||
public uint Flags { get; set; }
|
||||
public int TextureIndex { get; set; } // Actually byte
|
||||
public uint Reserved { get; set; }
|
||||
|
||||
public byte[] GsRegs { get; set; } // One GS primitive, CLAMP_1 and TEX0_1
|
||||
public byte[] GifTagFan { get; set; }
|
||||
public byte[] GifTagStrip { get; set; }
|
||||
|
||||
public List<VuVector> Vertices { get; } = new List<VuVector>();
|
||||
public List<Tuple<double, double, double>> VertexNormals { get; } = new List<Tuple<double, double, double>>();
|
||||
public List<Tuple<double, double>> STCoordinates { get; } = new List<Tuple<double, double>>();
|
||||
|
||||
// Flags broken out
|
||||
|
||||
public bool HasTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Flags & 0x10) != 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Flags = (uint)((Flags & ~0x10) | ((value ? 1u : 0) << 4));
|
||||
}
|
||||
}
|
||||
|
||||
public int GifTagIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)((Flags >> 9) & 7);
|
||||
}
|
||||
set
|
||||
{
|
||||
Flags = (uint)((Flags & ~0xe00) | (((uint)value & 7) << 9));
|
||||
}
|
||||
}
|
||||
|
||||
public bool DisableLighting
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Flags & 0x1000) != 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Flags = (uint)((Flags & ~0x1000) | ((value ? 1u : 0) << 12));
|
||||
}
|
||||
}
|
||||
|
||||
public int VertexCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return BitConverter.ToInt32(GifTagStrip, 0) & 0x7ff;
|
||||
}
|
||||
set
|
||||
{
|
||||
int num = BitConverter.ToInt32(GifTagStrip, 0);
|
||||
num = (num & ~0x7ff) | (value & 0x7ff);
|
||||
byte[] bytes = BitConverter.GetBytes(num);
|
||||
Buffer.BlockCopy(bytes, 0, GifTagStrip, 0, bytes.Length);
|
||||
|
||||
num = BitConverter.ToInt32(GifTagFan, 0);
|
||||
num = (num & ~0x7ff) | (value & 0x7ff);
|
||||
bytes = BitConverter.GetBytes(num);
|
||||
Buffer.BlockCopy(bytes, 0, GifTagFan, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
92
LibDgf/Mesh/Pdb.cs
Normal file
92
LibDgf/Mesh/Pdb.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using LibDgf.Ps2.Vif;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Mesh
|
||||
{
|
||||
public class Pdb
|
||||
{
|
||||
VuVector[] boundingBox;
|
||||
|
||||
public int BoundingBoxType { get; set; }
|
||||
public VuFloat BoundingBallSize { get; set; }
|
||||
public VuVector[] BoundingBox
|
||||
{
|
||||
get
|
||||
{
|
||||
return boundingBox;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null && value.Length != 8) throw new ArgumentException("Wrong number of vertices for bounding box.", nameof(value));
|
||||
boundingBox = value;
|
||||
}
|
||||
}
|
||||
public Tdb Specular { get; set; }
|
||||
public Tdb Diffuse { get; set; }
|
||||
public Tdb Metallic { get; set; }
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
var startOffset = br.BaseStream.Position;
|
||||
BoundingBoxType = br.ReadInt32();
|
||||
BoundingBallSize = br.ReadPs2Float();
|
||||
uint boundingBoxOffset = br.ReadUInt32();
|
||||
uint boundingBoxLength = br.ReadUInt32();
|
||||
uint[] tdbOffsets = new uint[3];
|
||||
uint[] tdbLengths = new uint[tdbOffsets.Length];
|
||||
for (int i = 0; i < tdbOffsets.Length; ++i)
|
||||
{
|
||||
tdbOffsets[i] = br.ReadUInt32();
|
||||
tdbLengths[i] = br.ReadUInt32();
|
||||
}
|
||||
|
||||
// Junk bytes 0xc8 to 0xcf here
|
||||
|
||||
if (boundingBoxLength != 0)
|
||||
{
|
||||
br.BaseStream.Seek(startOffset + boundingBoxOffset, SeekOrigin.Begin);
|
||||
BoundingBox = br.ReadBoundingBox();
|
||||
}
|
||||
else
|
||||
{
|
||||
BoundingBox = null;
|
||||
}
|
||||
|
||||
if (tdbLengths[0] != 0)
|
||||
{
|
||||
br.BaseStream.Seek(startOffset + tdbOffsets[0], SeekOrigin.Begin);
|
||||
Specular = new Tdb();
|
||||
Specular.Read(br);
|
||||
}
|
||||
else
|
||||
{
|
||||
Specular = null;
|
||||
}
|
||||
|
||||
if (tdbLengths[1] != 0)
|
||||
{
|
||||
br.BaseStream.Seek(startOffset + tdbOffsets[1], SeekOrigin.Begin);
|
||||
Diffuse = new Tdb();
|
||||
Diffuse.Read(br);
|
||||
}
|
||||
else
|
||||
{
|
||||
Diffuse = null;
|
||||
}
|
||||
|
||||
if (tdbLengths[2] != 0)
|
||||
{
|
||||
br.BaseStream.Seek(startOffset + tdbOffsets[2], SeekOrigin.Begin);
|
||||
Metallic = new Tdb();
|
||||
Metallic.Read(br);
|
||||
}
|
||||
else
|
||||
{
|
||||
Metallic = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
LibDgf/Mesh/Tdb.cs
Normal file
54
LibDgf/Mesh/Tdb.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using LibDgf.Ps2.Vif;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Mesh
|
||||
{
|
||||
public class Tdb
|
||||
{
|
||||
VuVector[] boundingBox;
|
||||
|
||||
public TdbFlags Flags { get; set; }
|
||||
public List<TdbTexture> Textures { get; } = new List<TdbTexture>();
|
||||
public VuVector[] BoundingBox
|
||||
{
|
||||
get
|
||||
{
|
||||
return boundingBox;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null && value.Length != 8) throw new ArgumentException("Wrong number of vertices for bounding box.", nameof(value));
|
||||
boundingBox = value;
|
||||
}
|
||||
}
|
||||
public Db2 Mesh { get; set; }
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
var startPos = br.BaseStream.Position;
|
||||
Flags = (TdbFlags)br.ReadByte();
|
||||
Textures.Clear();
|
||||
byte numTextures = br.ReadByte();
|
||||
for (int i = 0; i < numTextures; ++i)
|
||||
{
|
||||
var tex = new TdbTexture();
|
||||
tex.Read(br);
|
||||
Textures.Add(tex);
|
||||
}
|
||||
var read = br.BaseStream.Position - startPos;
|
||||
var aligned = (read + 15) & ~15;
|
||||
br.BaseStream.Seek(aligned - read, SeekOrigin.Current);
|
||||
|
||||
if ((Flags & TdbFlags.SkipBoundingBox) == 0)
|
||||
{
|
||||
BoundingBox = br.ReadBoundingBox();
|
||||
}
|
||||
|
||||
Mesh = new Db2();
|
||||
Mesh.Read(br);
|
||||
}
|
||||
}
|
||||
}
|
13
LibDgf/Mesh/TdbFlags.cs
Normal file
13
LibDgf/Mesh/TdbFlags.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Mesh
|
||||
{
|
||||
[Flags]
|
||||
public enum TdbFlags : byte
|
||||
{
|
||||
None = 0,
|
||||
SkipBoundingBox = 1,
|
||||
}
|
||||
}
|
21
LibDgf/Mesh/TdbTexture.cs
Normal file
21
LibDgf/Mesh/TdbTexture.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Mesh
|
||||
{
|
||||
public class TdbTexture
|
||||
{
|
||||
public ushort DatIndex { get; set; }
|
||||
public ushort ImageBufferBase { get; set; }
|
||||
public ushort ClutBufferBase { get; set; }
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
DatIndex = br.ReadUInt16();
|
||||
ImageBufferBase = br.ReadUInt16();
|
||||
ClutBufferBase = br.ReadUInt16();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue