From 00e977b3dbb8f447b034b7be387ee1a1cce0598c Mon Sep 17 00:00:00 2001 From: Treeki Date: Fri, 25 Feb 2011 22:08:57 +0100 Subject: start of a brres writer --- NW4RTools/BrresReader.cs | 11 ++- NW4RTools/BrresWriter.cs | 121 +++++++++++++++++++++++++++++++ NW4RTools/Models/OpenGL/GLModel.cs | 14 ++-- NW4RTools/NW4RTools.csproj | 2 + NW4RTools/NW4RTools.pidb | Bin 541003 -> 545355 bytes NW4RTools/OutputStream.cs | 131 ++++++++++++++++++++++++++++++++++ NW4RTools/bin/Debug/NW4RTools.dll | Bin 175616 -> 181760 bytes NW4RTools/bin/Debug/NW4RTools.dll.mdb | Bin 94193 -> 95922 bytes 8 files changed, 272 insertions(+), 7 deletions(-) create mode 100644 NW4RTools/BrresWriter.cs create mode 100644 NW4RTools/OutputStream.cs (limited to 'NW4RTools') diff --git a/NW4RTools/BrresReader.cs b/NW4RTools/BrresReader.cs index 8b48ef3..518096d 100644 --- a/NW4RTools/BrresReader.cs +++ b/NW4RTools/BrresReader.cs @@ -44,7 +44,7 @@ namespace NW4RTools { UInt32 blkSize = ins.ReadUInt32(); using (var c = Debug.Push("Root Dictionary")) { - ReadAndParseDict(ins, ParseRootEntry); + ReadAndParseDict(ins, ParseRootEntry, "Root Dictionary"); } @@ -248,8 +248,13 @@ namespace NW4RTools { using (var c2 = Debug.Push("Shapes")) mdl.Shapes = ReadAndConvertDict(ins.At(startPos + shapeOffset), ConvertModelShape); - using (var c2 = Debug.Push("Texture Lookup for Texture Info/Material Pairing")) - mdl.PairingLookupByTexture = ReadAndConvertDict>(ins.At(startPos + textureOffset), ConvertPairingList); + if (textureOffset != 0) { + using (var c2 = Debug.Push("Texture Lookup for Texture Info/Material Pairing")) + mdl.PairingLookupByTexture = ReadAndConvertDict>(ins.At(startPos + textureOffset), ConvertPairingList); + } else { + mdl.PairingLookupByTexture = new ResDict>(); + Debug.Send("Texture Lookup for Texture Info/Material Pairing: none"); + } if (paletteOffset != 0) { using (var c2 = Debug.Push("Palette Lookup for Texture Info/Material Pairing")) diff --git a/NW4RTools/BrresWriter.cs b/NW4RTools/BrresWriter.cs new file mode 100644 index 0000000..5590ab5 --- /dev/null +++ b/NW4RTools/BrresWriter.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +using NW4RTools.Models; + +namespace NW4RTools { + public class BrresWriter { + public static byte[] WriteFile(ResFile file) { + return new BrresWriter().Save(file); + } + + + + private ResFile File; + private ILogger Debug; + private SortedDictionary OffsetMap; + private OutputStream Output; + + private BrresWriter() { + Debug = new ConsoleLogger(); + OffsetMap = new SortedDictionary(); + } + + private byte[] Save(ResFile file) { + Output = new OutputStream(ByteEndian.BigEndian); + File = file; + + using (var c = Debug.Push("Offset Calculation")) + CalculateRoot(); + + Output.WriteBytes(StringTableData.GetBuffer()); + + return Output.GetBuffer(); + } + + // OK, here's how I'm going to code this: kinda like how BrawlLib works, first I'll calculate the size of + // each written element, and use that to build up a list of offsets. Then, I'll actually write out the data. + // This code will also handle building the string table. + + #region Offset/String Table Calculation + private int CurrentPos; + + private void CalculateRoot() { + // Where it all starts! + InitialiseStringTable(); + + // First up: BRRES header + CurrentPos = 0x10; + + // First block, and ResDict + CurrentPos += 8; + CurrentPos += GetSizeForResDict(File); + + // Now do each ResDict in the File + foreach (object dict in File.Values) { + CurrentPos += GetSizeForResDict(dict as ResDict); + } + + // OK, so that's done. Process each type + foreach (var name in File.Keys) { + AddString(name); + switch (name) { + case "3DModels(NW4R)": + // do that stuff + break; + default: + Debug.Send("[[ UNIMPLEMENTED {0} ]]", name); + break; + } + } + + // ... and done with that. Build the string table and go! + CalculateStringTable(); + } + + + private int GetSizeForResDict(ResDict dict) { + return 8 + ((dict.Count + 1) * 0x10); + } + + #endregion + + #region String Table Handling + // Contains the strings while they're being pulled from the ResFile data + private List StringTable; + + // Once every string used in the .brres is found, CalculateStringTable() is called, which + // writes the table to an OutputStream and saves every offset + private Dictionary StringTableOffsets; + + private OutputStream StringTableData; + + + // Called at the start of the process + private void InitialiseStringTable() { + StringTable = new List(); + } + + private void AddString(string str) { + if (!StringTable.Contains(str)) { + StringTable.Add(str); + } + } + + private void CalculateStringTable() { + StringTable.Sort(); + + StringTableOffsets = new Dictionary(); + StringTableData = new OutputStream(ByteEndian.BigEndian); + + foreach (var s in StringTable) { + // Add 4 because the Names are referenced by the string data, and not by the ResName struct itself + StringTableOffsets[s] = StringTableData.Position + 4; + StringTableData.WriteName(s); + } + } + #endregion + } +} + diff --git a/NW4RTools/Models/OpenGL/GLModel.cs b/NW4RTools/Models/OpenGL/GLModel.cs index 315415e..8ca3f31 100644 --- a/NW4RTools/Models/OpenGL/GLModel.cs +++ b/NW4RTools/Models/OpenGL/GLModel.cs @@ -17,7 +17,11 @@ namespace NW4RTools.Models.OpenGL { SourceModel = rf.GetGroup("3DModels(NW4R)")[modelName]; // cache some stuff - m_textureGroup = rf.GetGroup("Textures(NW4R)"); + try { + m_textureGroup = rf.GetGroup("Textures(NW4R)"); + } catch (KeyNotFoundException) { + // boo + } } @@ -162,9 +166,11 @@ namespace NW4RTools.Models.OpenGL { //CalculateNodes(); - foreach (var insn in SourceModel.Bytecode["DrawOpa"].Instructions) { - if (insn is ByteCode.DrawShapeInstruction) { - DrawShape(insn as ByteCode.DrawShapeInstruction); + if (SourceModel.Bytecode.ContainsKey("DrawOpa")) { + foreach (var insn in SourceModel.Bytecode["DrawOpa"].Instructions) { + if (insn is ByteCode.DrawShapeInstruction) { + DrawShape(insn as ByteCode.DrawShapeInstruction); + } } } diff --git a/NW4RTools/NW4RTools.csproj b/NW4RTools/NW4RTools.csproj index e1da0e8..3afef3b 100644 --- a/NW4RTools/NW4RTools.csproj +++ b/NW4RTools/NW4RTools.csproj @@ -70,6 +70,8 @@ + + diff --git a/NW4RTools/NW4RTools.pidb b/NW4RTools/NW4RTools.pidb index d805eec..317dedf 100644 Binary files a/NW4RTools/NW4RTools.pidb and b/NW4RTools/NW4RTools.pidb differ diff --git a/NW4RTools/OutputStream.cs b/NW4RTools/OutputStream.cs new file mode 100644 index 0000000..3f250a2 --- /dev/null +++ b/NW4RTools/OutputStream.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; + +namespace NW4RTools { + public class OutputStream { + // TODO: look into making this (and InputStream) inherit from Stream, or something + public readonly ByteEndian Endian; + private readonly bool MustReverseArrays; + private readonly System.IO.MemoryStream BaseStream; + + public int Position { + get { return (int)BaseStream.Position; } + } + + public byte[] GetBuffer() { + return BaseStream.ToArray(); + } + + public OutputStream() { + BaseStream = new MemoryStream(); + Endian = ByteEndian.BigEndian; + MustReverseArrays = BitConverter.IsLittleEndian; + } + + public OutputStream(ByteEndian endian) { + BaseStream = new MemoryStream(); + Endian = endian; + + if (Endian == ByteEndian.BigEndian) + MustReverseArrays = BitConverter.IsLittleEndian; + else + MustReverseArrays = !BitConverter.IsLittleEndian; + } + + public void Seek(int pos) { + if (pos < 0 || pos > BaseStream.Length) + throw new ArgumentOutOfRangeException(); + + BaseStream.Position = pos; + } + + public void WriteBytes(byte[] data) { + BaseStream.Write(data, 0, data.Length); + } + + private void WriteReversedBytes(byte[] data) { + // TODO: figure out if this modifies the array + if (MustReverseArrays) + Array.Reverse(data); + BaseStream.Write(data, 0, data.Length); + } + + public void WriteByte(byte val) { + BaseStream.WriteByte(val); + } + + public void WriteSByte(sbyte val) { + WriteByte(unchecked((byte)val)); + } + + public void WriteInt16(Int16 val) { + WriteReversedBytes(BitConverter.GetBytes(val)); + } + + public void WriteUInt16(UInt16 val) { + WriteReversedBytes(BitConverter.GetBytes(val)); + } + + public void WriteInt32(Int32 val) { + WriteReversedBytes(BitConverter.GetBytes(val)); + } + + public void WriteUInt32(UInt32 val) { + WriteReversedBytes(BitConverter.GetBytes(val)); + } + + public void WriteFloat(float val) { + WriteReversedBytes(BitConverter.GetBytes(val)); + } + + public void WriteDouble(double val) { + WriteReversedBytes(BitConverter.GetBytes(val)); + } + + public void WriteColor(Color col) { + WriteByte(col.r); + WriteByte(col.g); + WriteByte(col.b); + WriteByte(col.a); + } + + public void WriteVec2(Vec2 vec) { + WriteFloat(vec.x); + WriteFloat(vec.y); + } + + public void WriteVec3(Vec3 vec) { + WriteFloat(vec.x); + WriteFloat(vec.y); + WriteFloat(vec.z); + } + + public void WriteMatrix(Matrix m) { + WriteFloat(m.v00); + WriteFloat(m.v01); + WriteFloat(m.v02); + WriteFloat(m.v03); + WriteFloat(m.v10); + WriteFloat(m.v11); + WriteFloat(m.v12); + WriteFloat(m.v13); + WriteFloat(m.v20); + WriteFloat(m.v21); + WriteFloat(m.v22); + WriteFloat(m.v23); + } + + public void WriteName(string name) { + byte[] encoded = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(name); + WriteInt32(encoded.Length); + WriteBytes(encoded); + + if ((encoded.Length & 3) != 0) { + for (int i = 4 - (encoded.Length & 3); i > 0; i--) { + WriteByte(0); + } + } + } + } +} + diff --git a/NW4RTools/bin/Debug/NW4RTools.dll b/NW4RTools/bin/Debug/NW4RTools.dll index 0fe74f3..3962f15 100755 Binary files a/NW4RTools/bin/Debug/NW4RTools.dll and b/NW4RTools/bin/Debug/NW4RTools.dll differ diff --git a/NW4RTools/bin/Debug/NW4RTools.dll.mdb b/NW4RTools/bin/Debug/NW4RTools.dll.mdb index f7eb0df..f5f1318 100644 Binary files a/NW4RTools/bin/Debug/NW4RTools.dll.mdb and b/NW4RTools/bin/Debug/NW4RTools.dll.mdb differ -- cgit v1.2.3