diff options
-rw-r--r-- | NW4RTools/BrresReader.cs | 46 | ||||
-rw-r--r-- | NW4RTools/DisplayList.cs | 25 | ||||
-rw-r--r-- | NW4RTools/Enums.cs | 13 | ||||
-rw-r--r-- | NW4RTools/InputStream.cs | 12 | ||||
-rw-r--r-- | NW4RTools/Models/Shape.cs | 10 | ||||
-rw-r--r-- | NW4RTools/Models/VertexData.cs | 102 | ||||
-rw-r--r-- | NW4RTools/NW4RTools.csproj | 3 | ||||
-rw-r--r-- | NW4RTools/ObjWriter.cs | 130 | ||||
-rwxr-xr-x | NW4RTools/bin/Debug/NW4RTools.dll | bin | 31744 -> 36352 bytes | |||
-rw-r--r-- | NW4RTools/bin/Debug/NW4RTools.dll.mdb | bin | 11043 -> 12709 bytes | |||
-rw-r--r-- | TestApp/Main.cs | 12 | ||||
-rwxr-xr-x | TestApp/bin/Debug/NW4RTools.dll | bin | 31744 -> 36352 bytes | |||
-rw-r--r-- | TestApp/bin/Debug/NW4RTools.dll.mdb | bin | 11043 -> 12427 bytes | |||
-rwxr-xr-x | TestApp/bin/Debug/TestApp.exe | bin | 3584 -> 4096 bytes | |||
-rw-r--r-- | TestApp/bin/Debug/TestApp.exe.mdb | bin | 416 -> 447 bytes |
15 files changed, 332 insertions, 21 deletions
diff --git a/NW4RTools/BrresReader.cs b/NW4RTools/BrresReader.cs index eeccd94..49f2edb 100644 --- a/NW4RTools/BrresReader.cs +++ b/NW4RTools/BrresReader.cs @@ -147,6 +147,11 @@ namespace NW4RTools { // Load vertex data // COMMENTED OUT TO MAKE DEUBG OUTPUT CLEARER FOR NOW + VtxPosIndexLookup = new Dictionary<int, VertexPosData>(); + VtxNrmIndexLookup = new Dictionary<int, VertexNrmData>(); + VtxClrIndexLookup = new Dictionary<int, VertexClrData>(); + VtxTexCoordIndexLookup = new Dictionary<int, VertexTexCoordData>(); + using (var c2 = Debug.Push("Vertex Position Data")) mdl.VtxPosData = ReadAndConvertDict<VertexPosData>(ins.At(startPos + vtxPosOffset), ConvertVtxPosData); using (var c2 = Debug.Push("Vertex Normal Data")) @@ -341,9 +346,11 @@ namespace NW4RTools { Int32 dataOffset = ins.ReadInt32(); Int32 nameOffset = ins.ReadInt32(); + // Note: we're relying on this value to be correct, for Shape mappings n.Index = ins.ReadUInt32(); - n.ComponentCount = ins.ReadUInt32(); - n.ComponentType = ins.ReadUInt32(); + + n.ComponentCount = (CompCount)ins.ReadUInt32(); + n.ComponentType = (CompType)ins.ReadUInt32(); n.Fraction = ins.ReadByte(); n.EntrySize = ins.ReadByte(); n.EntryCount = ins.ReadUInt16(); @@ -351,6 +358,11 @@ namespace NW4RTools { n.Data = ins.ReadBytes(n.EntrySize * n.EntryCount); } + private Dictionary<int, Models.VertexPosData> VtxPosIndexLookup; + private Dictionary<int, Models.VertexNrmData> VtxNrmIndexLookup; + private Dictionary<int, Models.VertexClrData> VtxClrIndexLookup; + private Dictionary<int, Models.VertexTexCoordData> VtxTexCoordIndexLookup; + private Models.VertexPosData ConvertVtxPosData(string name, InputStream ins) { var n = new Models.VertexPosData(); @@ -361,6 +373,8 @@ namespace NW4RTools { n.Minimum = ins.ReadVec3(); n.Maximum = ins.ReadVec3(); + VtxPosIndexLookup[(int)n.Index] = n; + return n; } @@ -370,6 +384,8 @@ namespace NW4RTools { OffsetMap.Add(ins.Position, "VertexNrmData: " + name); LoadVertexDataBase(ins, n); + + VtxNrmIndexLookup[(int)n.Index] = n; return n; } @@ -380,6 +396,8 @@ namespace NW4RTools { OffsetMap.Add(ins.Position, "VertexClrData: " + name); LoadVertexDataBase(ins, n); + + VtxClrIndexLookup[(int)n.Index] = n; return n; } @@ -394,6 +412,8 @@ namespace NW4RTools { n.Minimum = ins.ReadVec2(); n.Maximum = ins.ReadVec2(); + VtxTexCoordIndexLookup[(int)n.Index] = n; + return n; } @@ -638,19 +658,25 @@ namespace NW4RTools { s.PolygonCount = ins.ReadUInt32(); // 0x48 - s.PosDataIndex = ins.ReadInt16(); + s.PosData = VtxPosIndexLookup[ins.ReadInt16()]; + // 0x4A - s.NrmDataIndex = ins.ReadInt16(); + short nrmIndex = ins.ReadInt16(); + s.NrmData = nrmIndex == -1 ? null : VtxNrmIndexLookup[nrmIndex]; // 0x4C - s.ClrDataIndex = new short[2]; - for (int i = 0; i < 2; i++) - s.ClrDataIndex[i] = ins.ReadInt16(); + s.ClrData = new VertexClrData[2]; + for (int i = 0; i < 2; i++) { + short clrIndex = ins.ReadInt16(); + s.ClrData[i] = clrIndex == -1 ? null : VtxClrIndexLookup[clrIndex]; + } // 0x50 - s.TexCoordDataIndex = new short[8]; - for (int i = 0; i < 8; i++) - s.TexCoordDataIndex[i] = ins.ReadInt16(); + s.TexCoordData = new VertexTexCoordData[8]; + for (int i = 0; i < 8; i++) { + short tcIndex = ins.ReadInt16(); + s.TexCoordData[i] = tcIndex == -1 ? null : VtxTexCoordIndexLookup[tcIndex]; + } // 0x60 s.FurVecDataIndex = ins.ReadInt16(); diff --git a/NW4RTools/DisplayList.cs b/NW4RTools/DisplayList.cs new file mode 100644 index 0000000..6885f39 --- /dev/null +++ b/NW4RTools/DisplayList.cs @@ -0,0 +1,25 @@ +using System; + +// COMPLETELY UNFINISHED + +namespace NW4RTools { + public class DisplayList { + public class Command { + public virtual byte GetStartByte() { + return 0; + } + + //public abstract void Write(OutputStream os); + } + + public class DrawCommand : Command { + public PrimitiveType Primitive; + } + + + + public DisplayList() { + } + } +} + diff --git a/NW4RTools/Enums.cs b/NW4RTools/Enums.cs new file mode 100644 index 0000000..21b6e8d --- /dev/null +++ b/NW4RTools/Enums.cs @@ -0,0 +1,13 @@ +using System; + +namespace NW4RTools { + public enum PrimitiveType { + Quads = 0, + Triangles = 2, + TriangleStrip = 3, + TriangleFan = 4, + Lines = 5, + LineStrip = 6, + Points = 7 + } +} diff --git a/NW4RTools/InputStream.cs b/NW4RTools/InputStream.cs index 3a776b4..134cb93 100644 --- a/NW4RTools/InputStream.cs +++ b/NW4RTools/InputStream.cs @@ -29,8 +29,14 @@ namespace NW4RTools { MustReverseArrays = !BitConverter.IsLittleEndian; } + public bool AtEnd { + get { + return (Position == Data.Length); + } + } + public void Seek(int pos) { - if (pos < 0 || pos >= Data.Length) + if (pos < 0 || pos > Data.Length) throw new ArgumentOutOfRangeException(); Position = pos; @@ -60,6 +66,10 @@ namespace NW4RTools { return ret; } + public SByte ReadSByte() { + return unchecked((sbyte)ReadByte()); + } + public Int16 ReadInt16() { return BitConverter.ToInt16(ReadReversedBytes(2), 0); } diff --git a/NW4RTools/Models/Shape.cs b/NW4RTools/Models/Shape.cs index 72cdbaa..88d6670 100644 --- a/NW4RTools/Models/Shape.cs +++ b/NW4RTools/Models/Shape.cs @@ -12,11 +12,11 @@ namespace NW4RTools.Models { public UInt32 VertexCount; public UInt32 PolygonCount; - // todo: use refs for this - public Int16 PosDataIndex; - public Int16 NrmDataIndex; - public Int16[] ClrDataIndex; - public Int16[] TexCoordDataIndex; + public VertexPosData PosData; + public VertexNrmData NrmData; + public VertexClrData[] ClrData; + public VertexTexCoordData[] TexCoordData; + public Int16 FurVecDataIndex; public Int16 FurPosDataIndex; diff --git a/NW4RTools/Models/VertexData.cs b/NW4RTools/Models/VertexData.cs index d8733b3..b1f65cd 100644 --- a/NW4RTools/Models/VertexData.cs +++ b/NW4RTools/Models/VertexData.cs @@ -1,10 +1,31 @@ using System; namespace NW4RTools.Models { - public class VertexDataBase { + public enum CompCount { + Position2 = 0, + Position3 = 1, + Normal3 = 0, + Color3 = 0, + Color4 = 1, + TexCoord1 = 0, + TexCoord2 = 1 + } + + + public enum CompType { + UInt8 = 0, + Int8 = 1, + UInt16 = 2, + Int16 = 3, + Float32 = 4 + } + + + public abstract class VertexDataBase { public UInt32 Index; - public UInt32 ComponentCount, ComponentType; // todo: enums + public CompCount ComponentCount; + public CompType ComponentType; public byte Fraction /* Not used for colours */, EntrySize; public UInt16 EntryCount; @@ -13,6 +34,41 @@ namespace NW4RTools.Models { public VertexDataBase() { } + + public float[] GetEntry(int index) { + float[] ret = new float[GetRealCount()]; + + float scale = 1.0f / (1 << Fraction); + + //Console.WriteLine("Getting index {0}, count {1} size {2} length {3} offset {4}", index, EntryCount, EntrySize, Data.Length, index * EntrySize); + InputStream ins = new InputStream(Data); + ins.Seek(index * EntrySize); + + for (int i = 0; i < ret.Length; i++) { + switch (ComponentType) { + case CompType.UInt8: + break; + case CompType.Int8: + ret[i] = (float)ins.ReadSByte() * scale; + break; + case CompType.UInt16: + ret[i] = (float)ins.ReadUInt16() * scale; + break; + case CompType.Int16: + ret[i] = (float)ins.ReadInt16() * scale; + break; + case CompType.Float32: + ret[i] = ins.ReadFloat(); + break; + default: + throw new NotImplementedException(String.Format("unimplemented type {0}", (int)ComponentType)); + } + } + + return ret; + } + + public abstract int GetRealCount(); } @@ -21,18 +77,49 @@ namespace NW4RTools.Models { public VertexPosData() { } + + public override int GetRealCount() { + switch (ComponentCount) { + case CompCount.Position2: + return 2; + case CompCount.Position3: + return 3; + default: + return -1; + } + } } public class VertexNrmData : VertexDataBase { public VertexNrmData() { } + + public override int GetRealCount() { + switch (ComponentCount) { + case CompCount.Normal3: + return 3; + default: + return -1; + } + } } public class VertexClrData : VertexDataBase { public VertexClrData() { } + + public override int GetRealCount() { + switch (ComponentCount) { + case CompCount.Color3: + return 3; + case CompCount.Color4: + return 4; + default: + return -1; + } + } } @@ -41,6 +128,17 @@ namespace NW4RTools.Models { public VertexTexCoordData() { } + + public override int GetRealCount() { + switch (ComponentCount) { + case CompCount.TexCoord1: + return 1; + case CompCount.TexCoord2: + return 2; + default: + return -1; + } + } } } diff --git a/NW4RTools/NW4RTools.csproj b/NW4RTools/NW4RTools.csproj index 71ad2ba..954271d 100644 --- a/NW4RTools/NW4RTools.csproj +++ b/NW4RTools/NW4RTools.csproj @@ -50,6 +50,9 @@ <Compile Include="Models\Shader.cs" /> <Compile Include="Models\Shape.cs" /> <Compile Include="Models\TextureInfo.cs" /> + <Compile Include="ObjWriter.cs" /> + <Compile Include="Enums.cs" /> + <Compile Include="DisplayList.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> diff --git a/NW4RTools/ObjWriter.cs b/NW4RTools/ObjWriter.cs new file mode 100644 index 0000000..72a134c --- /dev/null +++ b/NW4RTools/ObjWriter.cs @@ -0,0 +1,130 @@ +using System; +using System.IO; +using System.Collections.Generic; +using NW4RTools.Models; + +namespace NW4RTools { + public class ObjWriter { + public static void WriteModel(TextWriter tw, ResFile file, string modelName) { + new ObjWriter(file).SaveModel(tw, modelName); + } + + + + ResFile CurrentFile; + Models.Model CurrentModel; + TextWriter Output; + + private ObjWriter(ResFile file) { + CurrentFile = file; + } + + Dictionary<Models.VertexPosData, int> VtxPosOffsets; + Dictionary<Models.VertexNrmData, int> VtxNrmOffsets; + Dictionary<Models.VertexTexCoordData, int> VtxTexCoordOffsets; + + public void SaveModel(TextWriter tw, string modelName) { + Output = tw; + CurrentModel = CurrentFile.GetGroup<Model>("3DModels(NW4R)")[modelName]; + + Output.WriteLine("# {0} exported by Treeki's NW4RTools", modelName); + Output.WriteLine("# {0}", DateTime.Now); + Output.WriteLine(); + + // Write vertex data pool + int Offset; + + VtxPosOffsets = new Dictionary<VertexPosData, int>(); + Offset = 1; + foreach (var kv in CurrentModel.VtxPosData) { + VtxPosOffsets[kv.Value] = Offset; + Output.WriteLine("# Vertex Positions: {0} [offset {1}]", kv.Key, Offset); + + for (int i = 0; i < kv.Value.EntryCount; i++) { + float[] v = kv.Value.GetEntry(i); + Output.WriteLine("v {0} {1} {2}", v[0], v[1], v[2]); + } + + Offset += kv.Value.EntryCount; + } + + VtxNrmOffsets = new Dictionary<VertexNrmData, int>(); + Offset = 1; + foreach (var kv in CurrentModel.VtxNrmData) { + VtxNrmOffsets[kv.Value] = Offset; + Output.WriteLine("# Vertex Normals: {0} [offset {1}]", kv.Key, Offset); + + for (int i = 0; i < kv.Value.EntryCount; i++) { + float[] v = kv.Value.GetEntry(i); + Output.WriteLine("vn {0} {1} {2}", v[0], v[1], v[2]); + } + + Offset += kv.Value.EntryCount; + } + + VtxTexCoordOffsets = new Dictionary<VertexTexCoordData, int>(); + Offset = 1; + foreach (var kv in CurrentModel.VtxTexCoordData) { + VtxTexCoordOffsets[kv.Value] = Offset; + Output.WriteLine("# Vertex TexCoords: {0} [offset {1}]", kv.Key, Offset); + + for (int i = 0; i < kv.Value.EntryCount; i++) { + float[] v = kv.Value.GetEntry(i); + Output.WriteLine("vt {0} {1}", v[0], v[1]); + } + + Offset += kv.Value.EntryCount; + } + + Output.WriteLine(); + + // Write shapes + // TODO: replace with something using the Bytecode + foreach (var kv in CurrentModel.Shapes) { + Output.WriteLine("g {0}", kv.Key); + + WriteShape(kv.Value); + + Output.WriteLine(); + } + + Output.Flush(); + } + + + private void WriteShape(Models.Shape shape) { + // parse the DisplayList + + int posOffset = VtxPosOffsets[shape.PosData]; + int nrmOffset = shape.NrmData == null ? -1 : VtxNrmOffsets[shape.NrmData]; + int tcOffset = shape.TexCoordData[0] == null ? -1 : VtxTexCoordOffsets[shape.TexCoordData[0]]; + // TODO: Better DisplayList parsing, in a similar fashion to ByteCode + var dl = new InputStream(shape.DisplayList2); + + while (true) { + if (dl.AtEnd) + break; + + byte cmd = dl.ReadByte(); + PrimitiveType prim = (PrimitiveType)cmd; + int vtxCount = dl.ReadUInt16(); + Output.WriteLine("# Primitive: {0} ({1} vertices)", prim, vtxCount); + + // I wonder if INDEX8 is ever used here? + // Going with INDEX16 for now. + + switch (prim) { + case PrimitiveType.TriangleStrip: + // De-stripify it! + + + break; + + default: + throw new NotImplementedException(); + } + } + } + } +} + diff --git a/NW4RTools/bin/Debug/NW4RTools.dll b/NW4RTools/bin/Debug/NW4RTools.dll Binary files differindex cb655f9..a1602c8 100755 --- a/NW4RTools/bin/Debug/NW4RTools.dll +++ b/NW4RTools/bin/Debug/NW4RTools.dll diff --git a/NW4RTools/bin/Debug/NW4RTools.dll.mdb b/NW4RTools/bin/Debug/NW4RTools.dll.mdb Binary files differindex 06fe2a2..f4fb376 100644 --- a/NW4RTools/bin/Debug/NW4RTools.dll.mdb +++ b/NW4RTools/bin/Debug/NW4RTools.dll.mdb diff --git a/TestApp/Main.cs b/TestApp/Main.cs index e6fa82f..f608262 100644 --- a/TestApp/Main.cs +++ b/TestApp/Main.cs @@ -1,13 +1,19 @@ using System; +using System.IO; using NW4RTools; namespace TestApp { class MainClass { public static void Main(string[] args) { - //byte[] file = System.IO.File.ReadAllBytes("/home/me/Games/Newer/miscStuff/CS_W1/g3d/model.brres"); - //byte[] file = System.IO.File.ReadAllBytes("/mnt/h/ISOs/NSMBWii/ais0.1.3/model.brres"); - byte[] file = System.IO.File.ReadAllBytes("/home/me/Games/Newer/miscStuff/bgB_4502/g3d/bgB_4502.brres"); + //byte[] file = File.ReadAllBytes("/home/me/Games/Newer/miscStuff/CS_W1/g3d/model.brres"); + //byte[] file = File.ReadAllBytes("/mnt/h/ISOs/NSMBWii/ais0.1.3/model.brres"); + byte[] file = File.ReadAllBytes("/home/me/Games/Newer/miscStuff/bgB_4502/g3d/bgB_4502.brres"); ResFile rf = BrresReader.LoadFile(file); + + var objFile = File.Open("/home/me/Games/Newer/miscStuff/bgB_4502/g3d/bgB_4502.obj", FileMode.OpenOrCreate); + var sw = new StreamWriter(objFile); + ObjWriter.WriteModel(sw, rf, "bgB_4502"); + objFile.Close(); } } } diff --git a/TestApp/bin/Debug/NW4RTools.dll b/TestApp/bin/Debug/NW4RTools.dll Binary files differindex cb655f9..1db8d9a 100755 --- a/TestApp/bin/Debug/NW4RTools.dll +++ b/TestApp/bin/Debug/NW4RTools.dll diff --git a/TestApp/bin/Debug/NW4RTools.dll.mdb b/TestApp/bin/Debug/NW4RTools.dll.mdb Binary files differindex 06fe2a2..847598a 100644 --- a/TestApp/bin/Debug/NW4RTools.dll.mdb +++ b/TestApp/bin/Debug/NW4RTools.dll.mdb diff --git a/TestApp/bin/Debug/TestApp.exe b/TestApp/bin/Debug/TestApp.exe Binary files differindex 37f5a57..2fd506e 100755 --- a/TestApp/bin/Debug/TestApp.exe +++ b/TestApp/bin/Debug/TestApp.exe diff --git a/TestApp/bin/Debug/TestApp.exe.mdb b/TestApp/bin/Debug/TestApp.exe.mdb Binary files differindex ed77ca1..c12c7f1 100644 --- a/TestApp/bin/Debug/TestApp.exe.mdb +++ b/TestApp/bin/Debug/TestApp.exe.mdb |