summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NW4RTools/BrresReader.cs46
-rw-r--r--NW4RTools/DisplayList.cs25
-rw-r--r--NW4RTools/Enums.cs13
-rw-r--r--NW4RTools/InputStream.cs12
-rw-r--r--NW4RTools/Models/Shape.cs10
-rw-r--r--NW4RTools/Models/VertexData.cs102
-rw-r--r--NW4RTools/NW4RTools.csproj3
-rw-r--r--NW4RTools/ObjWriter.cs130
-rwxr-xr-xNW4RTools/bin/Debug/NW4RTools.dllbin31744 -> 36352 bytes
-rw-r--r--NW4RTools/bin/Debug/NW4RTools.dll.mdbbin11043 -> 12709 bytes
-rw-r--r--TestApp/Main.cs12
-rwxr-xr-xTestApp/bin/Debug/NW4RTools.dllbin31744 -> 36352 bytes
-rw-r--r--TestApp/bin/Debug/NW4RTools.dll.mdbbin11043 -> 12427 bytes
-rwxr-xr-xTestApp/bin/Debug/TestApp.exebin3584 -> 4096 bytes
-rw-r--r--TestApp/bin/Debug/TestApp.exe.mdbbin416 -> 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
index cb655f9..a1602c8 100755
--- a/NW4RTools/bin/Debug/NW4RTools.dll
+++ b/NW4RTools/bin/Debug/NW4RTools.dll
Binary files differ
diff --git a/NW4RTools/bin/Debug/NW4RTools.dll.mdb b/NW4RTools/bin/Debug/NW4RTools.dll.mdb
index 06fe2a2..f4fb376 100644
--- a/NW4RTools/bin/Debug/NW4RTools.dll.mdb
+++ b/NW4RTools/bin/Debug/NW4RTools.dll.mdb
Binary files differ
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
index cb655f9..1db8d9a 100755
--- a/TestApp/bin/Debug/NW4RTools.dll
+++ b/TestApp/bin/Debug/NW4RTools.dll
Binary files differ
diff --git a/TestApp/bin/Debug/NW4RTools.dll.mdb b/TestApp/bin/Debug/NW4RTools.dll.mdb
index 06fe2a2..847598a 100644
--- a/TestApp/bin/Debug/NW4RTools.dll.mdb
+++ b/TestApp/bin/Debug/NW4RTools.dll.mdb
Binary files differ
diff --git a/TestApp/bin/Debug/TestApp.exe b/TestApp/bin/Debug/TestApp.exe
index 37f5a57..2fd506e 100755
--- a/TestApp/bin/Debug/TestApp.exe
+++ b/TestApp/bin/Debug/TestApp.exe
Binary files differ
diff --git a/TestApp/bin/Debug/TestApp.exe.mdb b/TestApp/bin/Debug/TestApp.exe.mdb
index ed77ca1..c12c7f1 100644
--- a/TestApp/bin/Debug/TestApp.exe.mdb
+++ b/TestApp/bin/Debug/TestApp.exe.mdb
Binary files differ