summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-03-05 05:25:14 +0100
committerTreeki <treeki@gmail.com>2011-03-05 05:25:14 +0100
commite962fd89af865d6e01522e9752f5fbd855ce128a (patch)
tree0fb19e74a2d87b2ece48152fee2b2f4ed963828c
parenta5b6dc1789f2e06a26fe6a0510aee04aeccdc70b (diff)
downloadnw4rtools-e962fd89af865d6e01522e9752f5fbd855ce128a.tar.gz
nw4rtools-e962fd89af865d6e01522e9752f5fbd855ce128a.zip
partially working obj importer. still untested in-game
-rw-r--r--NW4RTools.sln3
-rwxr-xr-xNW4RTools.suobin0 -> 16896 bytes
-rw-r--r--NW4RTools.userprefs29
-rw-r--r--NW4RTools/BrresWriter.cs99
-rw-r--r--NW4RTools/Enums.cs4
-rw-r--r--NW4RTools/Models/Material.cs13
-rw-r--r--NW4RTools/Models/OpenGL/GLModel.cs2
-rw-r--r--NW4RTools/Models/VertexData.cs52
-rw-r--r--NW4RTools/NW4RTools.csproj3
-rw-r--r--NW4RTools/NW4RTools.pidbbin556448 -> 579951 bytes
-rw-r--r--NW4RTools/ObjExporter.cs187
-rwxr-xr-xNW4RTools/ObjImporter.cs759
-rw-r--r--NW4RTools/ResFile.cs35
-rw-r--r--NW4RTools/Types.cs46
-rw-r--r--NW4RTools/VertexSettings.cs79
-rwxr-xr-xNW4RTools/bin/Debug/NW4RTools.dllbin222208 -> 232960 bytes
-rw-r--r--NW4RTools/bin/Debug/NW4RTools.dll.mdbbin109819 -> 112922 bytes
-rw-r--r--TestApp/Main.cs19
-rw-r--r--TestApp/RenderWindow.cs2
-rw-r--r--TestApp/TestApp.pidbbin4288 -> 4240 bytes
-rwxr-xr-xTestApp/bin/Debug/NW4RTools.dllbin206336 -> 232960 bytes
-rw-r--r--TestApp/bin/Debug/NW4RTools.dll.mdbbin102677 -> 112922 bytes
-rwxr-xr-xTestApp/bin/Debug/TestApp.exebin5632 -> 5632 bytes
-rw-r--r--TestApp/bin/Debug/TestApp.exe.mdbbin965 -> 979 bytes
24 files changed, 1270 insertions, 62 deletions
diff --git a/NW4RTools.sln b/NW4RTools.sln
index eb42975..224f5e3 100644
--- a/NW4RTools.sln
+++ b/NW4RTools.sln
@@ -38,11 +38,12 @@ Global
$3.MethodBraceStyle = EndOfLine
$3.ConstructorBraceStyle = EndOfLine
$3.DestructorBraceStyle = EndOfLine
- $3.BeforeMethodCallParentheses = False
$3.BeforeMethodDeclarationParentheses = False
+ $3.BeforeMethodCallParentheses = False
$3.BeforeConstructorDeclarationParentheses = False
$3.BeforeDelegateDeclarationParentheses = False
$3.NewParentheses = False
+ $3.SpacesBeforeBrackets = False
$3.inheritsSet = Mono
$3.inheritsScope = text/x-csharp
$3.scope = text/x-csharp
diff --git a/NW4RTools.suo b/NW4RTools.suo
new file mode 100755
index 0000000..372e67d
--- /dev/null
+++ b/NW4RTools.suo
Binary files differ
diff --git a/NW4RTools.userprefs b/NW4RTools.userprefs
index 59f34b8..d7da209 100644
--- a/NW4RTools.userprefs
+++ b/NW4RTools.userprefs
@@ -1,19 +1,22 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
- <MonoDevelop.Ide.Workbench ActiveDocument="NW4RTools/BrresWriter.cs">
+ <MonoDevelop.Ide.Workbench ActiveDocument="NW4RTools/ObjImporter.cs">
<Files>
- <File FileName="NW4RTools/BrresReader.cs" Line="115" Column="34" />
- <File FileName="NW4RTools/BrresWriter.cs" Line="582" Column="69" />
- <File FileName="NW4RTools/Texture.cs" Line="193" Column="6" />
- <File FileName="TestApp/Main.cs" Line="18" Column="24" />
- <File FileName="NW4RTools/InputStream.cs" Line="136" Column="1" />
- <File FileName="NW4RTools/Models/Shape.cs" Line="24" Column="29" />
- <File FileName="NW4RTools/Models/OpenGL/GLTexture.cs" Line="37" Column="18" />
- <File FileName="NW4RTools/OutputStream.cs" Line="105" Column="36" />
- <File FileName="NW4RTools/Models/Model.cs" Line="33" Column="44" />
- <File FileName="NW4RTools/Models/Material.cs" Line="39" Column="3" />
- <File FileName="NW4RTools/Models/TextureInfo.cs" Line="1" Column="1" />
- <File FileName="TestApp/AssemblyInfo.cs" Line="1" Column="1" />
+ <File FileName="NW4RTools/ObjImporter.cs" Line="635" Column="18" />
+ <File FileName="NW4RTools/ObjExporter.cs" Line="105" Column="25" />
+ <File FileName="NW4RTools/BrresReader.cs" Line="784" Column="11" />
+ <File FileName="NW4RTools/BrresWriter.cs" Line="648" Column="21" />
+ <File FileName="NW4RTools/Models/Model.cs" Line="1" Column="1" />
+ <File FileName="NW4RTools/Models/ByteCode.cs" Line="1" Column="1" />
+ <File FileName="TestApp/Main.cs" Line="19" Column="1" />
+ <File FileName="NW4RTools/Types.cs" Line="1" Column="1" />
+ <File FileName="NW4RTools/Models/Material.cs" Line="1" Column="1" />
+ <File FileName="NW4RTools/VertexSettings.cs" Line="184" Column="46" />
+ <File FileName="NW4RTools/Models/VertexData.cs" Line="238" Column="31" />
+ <File FileName="NW4RTools/Enums.cs" Line="23" Column="27" />
+ <File FileName="NW4RTools/Models/OpenGL/GLModel.cs" Line="302" Column="1" />
+ <File FileName="NW4RTools/InputStream.cs" Line="66" Column="1" />
+ <File FileName="TestApp/RenderWindow.cs" Line="19" Column="1" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
diff --git a/NW4RTools/BrresWriter.cs b/NW4RTools/BrresWriter.cs
index b93a71d..cf48cdd 100644
--- a/NW4RTools/BrresWriter.cs
+++ b/NW4RTools/BrresWriter.cs
@@ -42,6 +42,12 @@ namespace NW4RTools {
return Output.GetBuffer();
}
+
+ private void LogPosition(string text) {
+ Debug.Send("0x{0:X} : {1}", CurrentPos, text);
+ OffsetMap.Add(CurrentPos, text);
+ }
+
// 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.
@@ -106,7 +112,7 @@ namespace NW4RTools {
// Now do each ResDict in the File
foreach (var kv in File) {
- OffsetMap.Add(CurrentPos, "ResDict: " + kv.Key);
+ LogPosition("ResDict: " + kv.Key);
RootDictOffsets[kv.Value] = CurrentPos;
CurrentPos += GetSizeForResDict((kv.Value as ICollection).Count);
@@ -132,7 +138,7 @@ namespace NW4RTools {
// ... and done with that. Build the string table and go!
AlignCalcPos(4);
- OffsetMap.Add(CurrentPos, "String Table");
+ LogPosition("String Table");
CalculateStringTable();
}
@@ -169,61 +175,61 @@ namespace NW4RTools {
// This is used later to calculate the MDL0 block size easily
int startPos = CurrentPos;
- OffsetMap.Add(CurrentPos, "Model: " + kv.Key);
+ LogPosition("Model: " + kv.Key);
ModelOffsets.Add(model, CurrentPos);
CurrentPos += 0x4C;
- OffsetMap.Add(CurrentPos, "Model Info Struct for: " + kv.Key);
+ LogPosition("Model Info Struct for: " + kv.Key);
CurrentPos += 0x40;
- OffsetMap.Add(CurrentPos, "Matrix ID to Node ID Data for: " + kv.Key);
+ LogPosition("Matrix ID to Node ID Data for: " + kv.Key);
calcInfo.MatrixIDtoNodeID = CurrentPos;
CurrentPos += 4 + (model.MatrixIDtoNodeID.Length * 4);
- OffsetMap.Add(CurrentPos, "ResDict: ByteCode");
+ LogPosition("ResDict: ByteCode");
calcInfo.Bytecode = CurrentPos;
CurrentPos += GetSizeForResDict(model.Bytecode.Count);
- OffsetMap.Add(CurrentPos, "ResDict: Nodes");
+ LogPosition("ResDict: Nodes");
calcInfo.Nodes = CurrentPos;
CurrentPos += GetSizeForResDict(model.Nodes.Count);
- OffsetMap.Add(CurrentPos, "ResDict: VertexPosData");
+ LogPosition("ResDict: VertexPosData");
calcInfo.VtxPosData = CurrentPos;
CurrentPos += GetSizeForResDict(model.VtxPosData.Count);
if (model.VtxNrmData.Count > 0) {
- OffsetMap.Add(CurrentPos, "ResDict: VertexNrmData");
+ LogPosition("ResDict: VertexNrmData");
calcInfo.VtxNrmData = CurrentPos;
CurrentPos += GetSizeForResDict(model.VtxNrmData.Count);
}
if (model.VtxClrData.Count > 0) {
- OffsetMap.Add(CurrentPos, "ResDict: VertexClrData");
+ LogPosition("ResDict: VertexClrData");
calcInfo.VtxClrData = CurrentPos;
CurrentPos += GetSizeForResDict(model.VtxClrData.Count);
}
if (model.VtxTexCoordData.Count > 0) {
- OffsetMap.Add(CurrentPos, "ResDict: VertexTexCoordData");
+ LogPosition("ResDict: VertexTexCoordData");
calcInfo.VtxTexCoordData = CurrentPos;
CurrentPos += GetSizeForResDict(model.VtxTexCoordData.Count);
}
- OffsetMap.Add(CurrentPos, "ResDict: Materials");
+ LogPosition("ResDict: Materials");
calcInfo.Materials = CurrentPos;
CurrentPos += GetSizeForResDict(model.Materials.Count);
- OffsetMap.Add(CurrentPos, "ResDict: Shaders");
+ LogPosition("ResDict: Shaders");
calcInfo.Shaders = CurrentPos;
CurrentPos += GetSizeForResDict(model.Shaders.Count);
- OffsetMap.Add(CurrentPos, "ResDict: Shapes");
+ LogPosition("ResDict: Shapes");
calcInfo.Shapes = CurrentPos;
CurrentPos += GetSizeForResDict(model.Shapes.Count);
if (model.PairingLookupByTexture.Count > 0) {
- OffsetMap.Add(CurrentPos, "ResDict: Texture Lookup");
+ LogPosition("ResDict: Texture Lookup");
calcInfo.PairingLookupByTexture = CurrentPos;
CurrentPos += GetSizeForResDict(model.PairingLookupByTexture.Count);
}
@@ -250,7 +256,7 @@ namespace NW4RTools {
private void CalculatePairings(Model m, ResDict<List<TexMatPairing>> dict) {
foreach (var kv in dict) {
- OffsetMap.Add(CurrentPos, "Texture/Material Pairing List for: " + kv.Key);
+ LogPosition("Texture/Material Pairing List for: " + kv.Key);
PairingOffsets.Add(kv.Value, CurrentPos);
CurrentPos += 4 + (kv.Value.Count * 8);
@@ -262,7 +268,7 @@ namespace NW4RTools {
AddString(kv.Key);
ByteCode bc = kv.Value;
- OffsetMap.Add(CurrentPos, "ByteCode: " + kv.Key);
+ LogPosition("ByteCode: " + kv.Key);
BytecodeOffsets.Add(kv.Value, CurrentPos);
foreach (var insn in bc.Instructions) {
@@ -296,7 +302,7 @@ namespace NW4RTools {
foreach (var kv in m.Nodes) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "Node: " + kv.Key);
+ LogPosition("Node: " + kv.Key);
NodeOffsets.Add(kv.Value, CurrentPos);
CurrentPos += 0xD0;
@@ -307,7 +313,7 @@ namespace NW4RTools {
foreach (var kv in m.Materials) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "Material: " + kv.Key);
+ LogPosition("Material: " + kv.Key);
MaterialOffsets.Add(kv.Value, CurrentPos);
// Base material struct
@@ -336,7 +342,7 @@ namespace NW4RTools {
// Texture Infos
if (kv.Value.TextureInfos.Count > 0)
- OffsetMap.Add(CurrentPos, "Material Texture Infos: " + kv.Key);
+ LogPosition("Material Texture Infos: " + kv.Key);
for (int i = 0; i < kv.Value.TextureInfos.Count; i++) {
TextureInfoOffsets[kv.Value.TextureInfos[i]] = CurrentPos;
@@ -345,7 +351,7 @@ namespace NW4RTools {
// Display Lists
AlignCalcPos(0x20);
- OffsetMap.Add(CurrentPos, "Material Display Lists: " + kv.Key);
+ LogPosition("Material Display Lists: " + kv.Key);
MaterialDLOffsets[kv.Value] = CurrentPos;
CurrentPos += 0x20 + 0x80 + 0x40 + 0xA0;
}
@@ -391,7 +397,7 @@ namespace NW4RTools {
// This is a new shader, add it!
calcInfo.UniqueShaders.Add(kv.Value);
- OffsetMap.Add(CurrentPos, "Shader: " + kv.Key);
+ LogPosition("Shader: " + kv.Key);
ShaderOffsets.Add(kv.Value, CurrentPos);
CurrentPos += 0x200;
@@ -403,7 +409,7 @@ namespace NW4RTools {
foreach (var kv in m.Shapes) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "Shape: " + kv.Key);
+ LogPosition("Shape: " + kv.Key);
ShapeOffsets.Add(kv.Value, CurrentPos);
CurrentPos += 0x68;
@@ -416,12 +422,12 @@ namespace NW4RTools {
AlignCalcPos(0x20);
ShapeDL1Offsets.Add(kv.Value, CurrentPos);
- OffsetMap.Add(CurrentPos, "Shape DL 1: " + kv.Key);
+ LogPosition("Shape DL 1: " + kv.Key);
CurrentPos += (int)kv.Value.DLBufferSize1;
AlignCalcPos(0x20);
ShapeDL2Offsets.Add(kv.Value, CurrentPos);
- OffsetMap.Add(CurrentPos, "Shape DL 2: " + kv.Key);
+ LogPosition("Shape DL 2: " + kv.Key);
CurrentPos += (int)kv.Value.DLBufferSize2;
// Should this line be after the final alignment?
@@ -436,7 +442,7 @@ namespace NW4RTools {
foreach (var kv in m.VtxPosData) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "VertexPosData: " + kv.Key);
+ LogPosition("VertexPosData: " + kv.Key);
VtxPosOffsets.Add(kv.Value, CurrentPos);
// Main data
@@ -446,7 +452,7 @@ namespace NW4RTools {
CurrentPos += 0x18;
AlignCalcPos(0x20);
- OffsetMap.Add(CurrentPos, "Data: " + kv.Key);
+ LogPosition("Data: " + kv.Key);
CurrentPos += kv.Value.EntryCount * kv.Value.EntrySize;
AlignCalcPos(0x20);
}
@@ -456,14 +462,14 @@ namespace NW4RTools {
foreach (var kv in m.VtxNrmData) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "VertexNrmData: " + kv.Key);
+ LogPosition("VertexNrmData: " + kv.Key);
VtxNrmOffsets.Add(kv.Value, CurrentPos);
// Main data
CurrentPos += 0x20;
AlignCalcPos(0x20);
- OffsetMap.Add(CurrentPos, "Data: " + kv.Key);
+ LogPosition("Data: " + kv.Key);
CurrentPos += kv.Value.EntryCount * kv.Value.EntrySize;
AlignCalcPos(0x20);
}
@@ -473,14 +479,14 @@ namespace NW4RTools {
foreach (var kv in m.VtxClrData) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "VertexClrData: " + kv.Key);
+ LogPosition("VertexClrData: " + kv.Key);
VtxClrOffsets.Add(kv.Value, CurrentPos);
// Main data
CurrentPos += 0x20;
AlignCalcPos(0x20);
- OffsetMap.Add(CurrentPos, "Data: " + kv.Key);
+ LogPosition("Data: " + kv.Key);
CurrentPos += kv.Value.EntryCount * kv.Value.EntrySize;
AlignCalcPos(0x20);
}
@@ -490,7 +496,7 @@ namespace NW4RTools {
foreach (var kv in m.VtxTexCoordData) {
AddString(kv.Key);
- OffsetMap.Add(CurrentPos, "VertexTexCoordData: " + kv.Key);
+ LogPosition("VertexTexCoordData: " + kv.Key);
VtxTexCoordOffsets.Add(kv.Value, CurrentPos);
// Main data
@@ -500,7 +506,7 @@ namespace NW4RTools {
CurrentPos += 0x10;
AlignCalcPos(0x20);
- OffsetMap.Add(CurrentPos, "Data: " + kv.Key);
+ LogPosition("Data: " + kv.Key);
CurrentPos += kv.Value.EntryCount * kv.Value.EntrySize;
AlignCalcPos(0x20);
}
@@ -523,14 +529,14 @@ namespace NW4RTools {
Debug.Send("Current: {0}", kv.Key);
- OffsetMap.Add(CurrentPos, "Texture: " + kv.Key);
+ LogPosition("Texture: " + kv.Key);
TextureOffsets.Add(kv.Value, CurrentPos);
CurrentPos += 0x30;
AlignCalcPos(0x20);
- OffsetMap.Add(CurrentPos, "Texture Data for: " + kv.Key);
+ LogPosition("Texture Data for: " + kv.Key);
TextureDataOffsets.Add(kv.Value, CurrentPos);
CurrentPos += texture.GetDataSize();
@@ -650,7 +656,7 @@ namespace NW4RTools {
Output.WriteInt32(calcInfo.Materials - startPos);
Output.WriteInt32(calcInfo.Shaders - startPos);
Output.WriteInt32(calcInfo.Shapes - startPos);
- Output.WriteInt32(calcInfo.PairingLookupByTexture - startPos);
+ Output.WriteInt32((calcInfo.PairingLookupByTexture == 0) ? 0 : (calcInfo.PairingLookupByTexture - startPos));
// Pairing lookup by palette, unhandled atm
Output.WriteInt32(0);
// Unknown extra data
@@ -673,8 +679,7 @@ namespace NW4RTools {
Output.WriteUInt32((uint)model.MatrixIDtoNodeID.Length);
Output.WriteByte(model.UsesNrmMtxArray ? (byte)1 : (byte)0);
Output.WriteByte(model.UsesTexMtxArray ? (byte)1 : (byte)0);
- // Padding
- Output.WriteInt16(0);
+ Output.AddPadding(2);
Output.WriteInt32(calcInfo.MatrixIDtoNodeID - infoStructPos);
Output.WriteVec3(model.Minimum);
Output.WriteVec3(model.Maximum);
@@ -700,7 +705,8 @@ namespace NW4RTools {
WriteResDict<Material>(model.Materials, MaterialOffsets);
WriteResDict<Shader>(model.Shaders, ShaderOffsets);
WriteResDict<Shape>(model.Shapes, ShapeOffsets);
- WriteResDict<List<TexMatPairing>>(model.PairingLookupByTexture, PairingOffsets);
+ if (model.PairingLookupByTexture.Count > 0)
+ WriteResDict<List<TexMatPairing>>(model.PairingLookupByTexture, PairingOffsets);
// TODO: Palette pairing lookups
@@ -735,6 +741,7 @@ namespace NW4RTools {
private void WriteBytecode(Model m) {
foreach (var kv in m.Bytecode) {
+ Debug.Send("Writing bytecode {0} @ offset {1:X}", kv.Key, Output.Position);
ByteCode bc = kv.Value;
foreach (var insn in bc.Instructions) {
@@ -787,6 +794,7 @@ namespace NW4RTools {
int currentIndex = 0;
foreach (var kv in m.Nodes) {
+ Debug.Send("Writing node {0} @ offset {1:X}", kv.Key, Output.Position);
Node node = kv.Value;
int startPos = Output.Position;
@@ -831,6 +839,7 @@ namespace NW4RTools {
int currentIndex = 0;
foreach (var kv in m.Materials) {
+ Debug.Send("Writing material {0} @ offset {1:X}", kv.Key, Output.Position);
Material mat = kv.Value;
int startPos = Output.Position;
@@ -897,8 +906,13 @@ namespace NW4RTools {
// ResTlutObj
Output.WriteUInt32(mat.TlutFlag);
- Output.WriteBytes(mat.TlutObj);
- Output.AddPadding(0x60 - mat.TlutObj.Length);
+
+ if (mat.TlutObj == null) {
+ Output.AddPadding(0x60);
+ } else {
+ Output.WriteBytes(mat.TlutObj);
+ Output.AddPadding(0x60 - mat.TlutObj.Length);
+ }
// ResTexSrt
// this one is a bit of a pain
@@ -1032,6 +1046,7 @@ namespace NW4RTools {
int currentIndex = 0;
foreach (var shader in ModelCalcInfos[m].UniqueShaders) {
+ Debug.Send("Writing shader @ offset {0:X}", Output.Position);
int startPos = Output.Position;
// Size, model offset, index
@@ -1058,6 +1073,7 @@ namespace NW4RTools {
int currentIndex = 0;
foreach (var kv in m.Shapes) {
+ Debug.Send("Writing shape {0} @ offset {1:X}", kv.Key, Output.Position);
Shape shape = kv.Value;
int startPos = Output.Position;
@@ -1142,6 +1158,7 @@ namespace NW4RTools {
int currentIndex = 0;
foreach (var kv in dict) {
+ Debug.Send("Writing vtxdata {0} @ offset {1:X}", kv.Key, Output.Position);
int startPos = Output.Position;
int structSize = 0x20;
diff --git a/NW4RTools/Enums.cs b/NW4RTools/Enums.cs
index 734eb9b..1ee089f 100644
--- a/NW4RTools/Enums.cs
+++ b/NW4RTools/Enums.cs
@@ -18,7 +18,9 @@ namespace NW4RTools {
LoadNrmMtxFromArray = 0x28,
LoadTexCoordMtxFromArray = 0x30,
LoadLightFromArray = 0x38,
- DrawPrimitiveMask = 0x80
+ DrawPrimitiveMask = 0x80,
+ // TODO: Figure out some better way to store this
+ PrimitiveShiftAmount = 3
}
diff --git a/NW4RTools/Models/Material.cs b/NW4RTools/Models/Material.cs
index 0bf0acc..519790c 100644
--- a/NW4RTools/Models/Material.cs
+++ b/NW4RTools/Models/Material.cs
@@ -18,6 +18,17 @@ namespace NW4RTools.Models {
public byte MapType;
public byte Flags;
public Matrix TexMatrix;
+
+ public SRTSettingInfo() {
+ ScaleX = 1.0f;
+ ScaleY = 1.0f;
+
+ CameraID = 0xFF;
+ LightID = 0xFf;
+ Flags = 1;
+
+ TexMatrix.Identity();
+ }
}
@@ -62,6 +73,8 @@ namespace NW4RTools.Models {
IndirectTexMtxCalcMethod2 = new byte[4];
TexObj = new byte[8][];
// todo
+ SRTSettings = new SRTSettingInfo[8];
+ ChanCtrls = new ChanCtrl[2];
TextureInfos = new List<TextureInfo>();
}
}
diff --git a/NW4RTools/Models/OpenGL/GLModel.cs b/NW4RTools/Models/OpenGL/GLModel.cs
index 8ca3f31..072ea00 100644
--- a/NW4RTools/Models/OpenGL/GLModel.cs
+++ b/NW4RTools/Models/OpenGL/GLModel.cs
@@ -257,7 +257,7 @@ namespace NW4RTools.Models.OpenGL {
break;
if ((cmd & (int)GXCommand.DrawPrimitiveMask) != 0) {
- PrimitiveType prim = (PrimitiveType)((cmd >> 3) & 7);
+ PrimitiveType prim = (PrimitiveType)((cmd >> (byte)GXCommand.PrimitiveShiftAmount) & 7);
int vtxCount = dl.ReadUInt16();
if ((cmd & 7) != 0)
diff --git a/NW4RTools/Models/VertexData.cs b/NW4RTools/Models/VertexData.cs
index 187b9aa..feb8eb6 100644
--- a/NW4RTools/Models/VertexData.cs
+++ b/NW4RTools/Models/VertexData.cs
@@ -60,6 +60,54 @@ namespace NW4RTools.Models {
}
}
+ public virtual void Save() {
+ int elementCount = Data[0].Length;
+ float scale = 1.0f / (1 << Fraction);
+ var output = new OutputStream();
+
+ switch (ComponentType) {
+ case VertexSettings.CompType.UInt8:
+ foreach (var array in Data) {
+ for (int i = 0; i < elementCount; i++) {
+ output.WriteByte((byte)(array[i] / scale));
+ }
+ }
+ break;
+ case VertexSettings.CompType.Int8:
+ foreach (var array in Data) {
+ for (int i = 0; i < elementCount; i++) {
+ output.WriteSByte((sbyte)(array[i] / scale));
+ }
+ }
+ break;
+ case VertexSettings.CompType.UInt16:
+ foreach (var array in Data) {
+ for (int i = 0; i < elementCount; i++) {
+ output.WriteUInt16((ushort)(array[i] / scale));
+ }
+ }
+ break;
+ case VertexSettings.CompType.Int16:
+ foreach (var array in Data) {
+ for (int i = 0; i < elementCount; i++) {
+ output.WriteInt16((short)(array[i] / scale));
+ }
+ }
+ break;
+ case VertexSettings.CompType.Float32:
+ foreach (var array in Data) {
+ for (int i = 0; i < elementCount; i++) {
+ output.WriteFloat(array[i]);
+ }
+ }
+ break;
+ default:
+ throw new NotImplementedException(String.Format("unimplemented type {0}", (int)ComponentType));
+ }
+
+ RawData = output.GetBuffer();
+ }
+
public abstract int GetRealCount();
}
@@ -186,6 +234,10 @@ namespace NW4RTools.Models {
return ret;
}
+
+ public override void Save() {
+ throw new NotImplementedException();
+ }
}
diff --git a/NW4RTools/NW4RTools.csproj b/NW4RTools/NW4RTools.csproj
index 80115cd..07fec58 100644
--- a/NW4RTools/NW4RTools.csproj
+++ b/NW4RTools/NW4RTools.csproj
@@ -59,7 +59,6 @@
<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" />
<Compile Include="VertexSettings.cs" />
@@ -76,6 +75,8 @@
<Compile Include="Models\Animation\TextureSRTAnim.cs" />
<Compile Include="Util\NVDXT.cs" />
<Compile Include="ColladaExporter.cs" />
+ <Compile Include="ObjExporter.cs" />
+ <Compile Include="ObjImporter.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/NW4RTools/NW4RTools.pidb b/NW4RTools/NW4RTools.pidb
index 5dbaf53..757d6c2 100644
--- a/NW4RTools/NW4RTools.pidb
+++ b/NW4RTools/NW4RTools.pidb
Binary files differ
diff --git a/NW4RTools/ObjExporter.cs b/NW4RTools/ObjExporter.cs
new file mode 100644
index 0000000..2bd791c
--- /dev/null
+++ b/NW4RTools/ObjExporter.cs
@@ -0,0 +1,187 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using NW4RTools.Models;
+
+namespace NW4RTools {
+ public class ObjExporter {
+ public static void WriteModel(TextWriter tw, ResFile file, string modelName) {
+ new ObjExporter(file).SaveModel(tw, modelName);
+ }
+
+
+
+ ResFile CurrentFile;
+ Models.Model CurrentModel;
+ TextWriter Output;
+
+ private ObjExporter(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) {
+ // first, parse the first DisplayList to get the attr info
+ // for now we'll hardcode the offsets. must be fixed later
+
+ var firstDL = new InputStream(shape.DisplayList1);
+ firstDL.Seek(0x0C);
+ UInt32 vtxDesc1 = firstDL.ReadUInt32();
+ firstDL.Seek(0x12);
+ UInt32 vtxDesc2 = firstDL.ReadUInt32();
+ firstDL.Seek(0x22);
+ UInt32 vtxAttr1 = firstDL.ReadUInt32();
+ firstDL.Seek(0x28);
+ UInt32 vtxAttr2 = firstDL.ReadUInt32();
+ firstDL.Seek(0x2E);
+ UInt32 vtxAttr3 = firstDL.ReadUInt32();
+
+ var vs = new VertexSettings();
+ vs.SetDesc(vtxDesc1, vtxDesc2);
+ vs.SetAttrFmt(vtxAttr1, vtxAttr2, vtxAttr3);
+
+ // get the Matrix to use
+ // todo: how to apply this?!
+ Matrix m = CurrentModel.Nodes[CurrentModel.MatrixIDtoNodeID[shape.MatrixID]].NodeMatrix;
+
+ // now parse the second 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();
+ if (cmd == 0)
+ break;
+
+ PrimitiveType prim = (PrimitiveType)((cmd >> 3) & 7);
+ int vtxCount = dl.ReadUInt16();
+ Output.WriteLine("# Primitive: {0} ({1} vertices)", prim, vtxCount);
+
+ // first, parse it into a list of vertices
+ GXIndexedVertex[] vtxs = new GXIndexedVertex[vtxCount];
+ string[] pVtxs = new string[vtxCount];
+
+ for (int i = 0; i < vtxCount; i++) {
+ vtxs[i].LoadFrom(dl, vs);
+
+ string tc = (vtxs[i].TexCoords[0] == -1) ? "" : (tcOffset + vtxs[i].TexCoords[0]).ToString();
+ string n = (vtxs[i].Normal == -1) ? "" : (nrmOffset + vtxs[i].Normal).ToString();
+ pVtxs[i] = String.Format(" {0}/{1}/{2}", posOffset + vtxs[i].Position, tc, n);
+ }
+
+ switch (prim) {
+ case PrimitiveType.Triangles:
+ for (int i = 0; i < vtxCount; i += 3) {
+ Output.WriteLine("f {0} {1} {2}", pVtxs[i], pVtxs[i + 1], pVtxs[i + 2]);
+ }
+
+ break;
+
+ case PrimitiveType.TriangleStrip:
+ // De-stripify it!
+ for (int i = 2; i < vtxCount; i++) {
+ Output.Write("f");
+ if ((i & 1) == 0) {
+ // Even number
+ Output.Write(pVtxs[i - 2]);
+ Output.Write(pVtxs[i - 1]);
+ Output.Write(pVtxs[i]);
+ } else {
+ // Odd number
+ Output.Write(pVtxs[i - 1]);
+ Output.Write(pVtxs[i - 2]);
+ Output.Write(pVtxs[i]);
+ }
+ Output.WriteLine();
+ }
+
+ break;
+
+ default:
+ Output.WriteLine("# UNIMPLEMENTED");
+ return;
+ }
+ }
+ }
+ }
+}
+
diff --git a/NW4RTools/ObjImporter.cs b/NW4RTools/ObjImporter.cs
new file mode 100755
index 0000000..41b9ea4
--- /dev/null
+++ b/NW4RTools/ObjImporter.cs
@@ -0,0 +1,759 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using NW4RTools.Models;
+
+namespace NW4RTools {
+ public class ObjImporter {
+ public static void ImportModel(string basePath, TextReader tr, ResFile file, string modelName) {
+ new ObjImporter(basePath, file, tr).ImportModel(modelName);
+ }
+
+
+
+ string BasePath;
+ ResFile CurrentFile;
+ Models.Model CurrentModel;
+ TextReader Input;
+
+ List<float[]> Positions;
+ List<float[]> Normals;
+ List<float[]> TexCoords;
+
+ Vec3 CurrentMinimum;
+ Vec3 CurrentMaximum;
+
+ private ObjImporter(string basePath, ResFile file, TextReader tr) {
+ BasePath = basePath;
+ CurrentFile = file;
+ Input = tr;
+ }
+
+ public void ImportModel(string modelName) {
+ var modelGroup = CurrentFile.CreateModelGroup();
+ var texGroup = CurrentFile.CreateTextureGroup();
+
+ // OK, so here's what I'm going to do:
+ // I'll read the file into an internal array and process commands as they come.
+
+ // Vertex position/normal/texcoord (v, vn, vt):
+ // -- These will be added into a list.
+
+ // Faces (f):
+ // -- These will be added into a list for the appropriate group.
+
+ // Set group (g):
+ // -- A shape will be created for this group. It will be added to DrawOpa.
+ // -- TODO: Add DrawXlu handling.
+
+ // Load material library (mtllib):
+ // -- The specified file will be loaded.
+ // -- All materials in it (and their associated textures) will be added to the model.
+
+ // Set current material (usemtl):
+ // -- A different material will be assigned for the current shape.
+
+ CurrentModel = new Model();
+ modelGroup.Add(modelName, CurrentModel);
+
+ // Before we start reading the OBJ file, prepare the model
+ CurrentModel.ScaleMode = Model.ScaleModeType.Standard;
+ CurrentModel.TexMatrixMode = Model.TexMatrixModeType.Maya;
+ CurrentModel.UsesNrmMtxArray = true;
+ // why?
+
+ // Todo: vertex count, triangle count
+ // Minimum, Maximum will be calc'd later
+ CurrentMinimum = new Vec3(0, 0, 0);
+ CurrentMaximum = new Vec3(0, 0, 0);
+
+ // Create one node
+ // Default settings from test_lift.brres
+ var newNode = new Node();
+ newNode.Flags = 0x31F;
+ newNode.Scale = new Vec3(1, 1, 1);
+ newNode.BoxMin = new Vec3(-16.0f, -16.0f, 0.0f);
+ newNode.BoxMax = new Vec3(16.0f, 16.0f, 0.0f);
+
+ newNode.NodeMatrix.v00 = 1;
+ newNode.NodeMatrix.v01 = 0;
+ newNode.NodeMatrix.v02 = 0;
+ newNode.NodeMatrix.v03 = 0;
+ newNode.NodeMatrix.v10 = 0;
+ newNode.NodeMatrix.v11 = 1;
+ newNode.NodeMatrix.v12 = 0;
+ newNode.NodeMatrix.v13 = 0;
+ newNode.NodeMatrix.v20 = 0;
+ newNode.NodeMatrix.v21 = 0;
+ newNode.NodeMatrix.v22 = 1;
+ newNode.NodeMatrix.v23 = 0;
+
+ newNode.NodeInvMatrix.v00 = 1;
+ newNode.NodeInvMatrix.v01 = -0;
+ newNode.NodeInvMatrix.v02 = 0;
+ newNode.NodeInvMatrix.v03 = 0;
+ newNode.NodeInvMatrix.v10 = -0;
+ newNode.NodeInvMatrix.v11 = 1;
+ newNode.NodeInvMatrix.v12 = -0;
+ newNode.NodeInvMatrix.v13 = 0;
+ newNode.NodeInvMatrix.v20 = 0;
+ newNode.NodeInvMatrix.v21 = -0;
+ newNode.NodeInvMatrix.v22 = 1;
+ newNode.NodeInvMatrix.v23 = 0;
+
+ CurrentModel.Nodes.Add("RootNode", newNode);
+
+ // Map it correctly
+ CurrentModel.MatrixIDtoNodeID = new int[1];
+ CurrentModel.MatrixIDtoNodeID[0] = 0;
+
+ // Now put together the NodeTree
+ var nodeTreeInsn = new ByteCode.AssignNodeToParentMtxInstruction();
+ nodeTreeInsn.NodeID = 0;
+ nodeTreeInsn.ParentMatrixID = 0;
+
+ var nodeTreeEndInsn = new ByteCode.DoneInstruction();
+
+ var nodeTree = new ByteCode();
+ nodeTree.Instructions.Add(nodeTreeInsn);
+ nodeTree.Instructions.Add(nodeTreeEndInsn);
+
+ CurrentModel.Bytecode.Add("NodeTree", nodeTree);
+
+ // Also, DrawOpa
+ var drawOpa = new ByteCode();
+ CurrentModel.Bytecode.Add("DrawOpa", drawOpa);
+
+ // Initial setup is done, let's go!
+ Positions = new List<float[]>();
+ Normals = new List<float[]>();
+ TexCoords = new List<float[]>();
+
+ string line;
+
+ while ((line = Input.ReadLine()) != null) {
+ line = line.Trim();
+
+ if (line.Length == 0 || line[0] == '#')
+ continue;
+
+ var parsed = line.Split(' ');
+
+ switch (parsed[0]) {
+ case "mtllib":
+ LoadMaterialLibrary(string.Join(" ", parsed, 1, parsed.Length - 1));
+ break;
+ case "v":
+ Positions.Add(ParseFloatArray(parsed, 1));
+ break;
+ case "vn":
+ Normals.Add(ParseFloatArray(parsed, 1));
+ break;
+ case "vt":
+ TexCoords.Add(ParseFloatArray(parsed, 1));
+ break;
+ case "f":
+ AddFace(parsed);
+ break;
+ case "g":
+ Console.WriteLine("Beginning shape {0}", parsed[1]);
+ BeginShape(parsed[1]);
+ break;
+ case "usemtl":
+ Console.WriteLine("Setting material {0}", parsed[1]);
+ SetMaterial(CurrentModel.Materials[parsed[1]]);
+ break;
+ default:
+ Console.WriteLine("Unhandled OBJ command: {0}", parsed[0]);
+ break;
+ }
+ }
+
+ EndShape();
+
+ // Parsing is finished. Let's finish up DrawOpa
+ drawOpa.Instructions.Add(new ByteCode.DoneInstruction());
+ }
+
+
+ private float[] ParseFloatArray(string[] src, int index) {
+ var output = new float[src.Length - index];
+
+ for (int i = index; i < src.Length; i++) {
+ output[i - index] = float.Parse(src[i]);
+ }
+
+ return output;
+ }
+
+
+ #region Materials
+ private void LoadMaterialLibrary(string libPath) {
+ string realPath = Path.Combine(BasePath, libPath);
+ Console.WriteLine("Loading material library from {0}", realPath);
+
+ var reader = File.OpenText(realPath);
+ string line;
+ Material currentMaterial = null;
+
+ while ((line = reader.ReadLine()) != null) {
+ line = line.Trim();
+
+ if (line.Length == 0 || line[0] == '#')
+ continue;
+
+ var parsed = line.Split(' ');
+
+ switch (parsed[0]) {
+ case "newmtl":
+ // Create a new material and initialise everything
+ // Default settings taken from Test_Lift material
+ currentMaterial = new Material();
+
+ currentMaterial.TexCoordGenCount = 1;
+ currentMaterial.ChanCount = 1;
+ currentMaterial.TevStageCount = 2;
+ currentMaterial.IndStageCount = 0;
+
+// This might need changing
+ currentMaterial.CullMode = 2;
+
+ currentMaterial.SRTSettings[0] = new SRTSettingInfo();
+
+ currentMaterial.ChanCtrls[0] = new ChanCtrl();
+ currentMaterial.ChanCtrls[0].Flags = 0x3F;
+ currentMaterial.ChanCtrls[0].MatColor.Rgba = 0xFFFFFFFF;
+ currentMaterial.ChanCtrls[0].AmbColor.Rgba = 0xFFFFFFFF;
+ currentMaterial.ChanCtrls[0].FlagC = 0x702;
+ currentMaterial.ChanCtrls[0].FlagA = 0x700;
+
+ currentMaterial.ChanCtrls[1] = new ChanCtrl();
+ currentMaterial.ChanCtrls[1].Flags = 0xF;
+ currentMaterial.ChanCtrls[1].MatColor.Rgba = 0x000000FF;
+ currentMaterial.ChanCtrls[1].AmbColor.Rgba = 0x00000000;
+ currentMaterial.ChanCtrls[1].FlagC = 0;
+ currentMaterial.ChanCtrls[1].FlagA = 0;
+
+// Default display lists, taken from test_lift
+ // The current version of MonoDevelop likes to make an awful mess
+ // of the indentation. There's nothing I can do about it. :/
+ currentMaterial.PixDL = new byte[] {
+ 0x61, 0xF3, 0x1E, 0xFF, 0x80,
+ 0x61, 0x40, 0x00, 0x00, 0x17,
+ 0x61, 0xFE, 0x00, 0xFF, 0xE3,
+ 0x61, 0x41, 0x00, 0x34, 0xA0,
+ 0x61, 0x42, 0x00, 0x00, 0x00,
+/* Padding */
+ 0, 0, 0, 0, 0,
+ 0, 0
+ };
+
+ currentMaterial.TevColorDL = new byte[] {
+ 0x61, 0xE2, 0x00, 0x00, 0xFF,
+ 0x61, 0xE3, 0x0F, 0xF0, 0xFF,
+ 0x61, 0xE3, 0x0F, 0xF0, 0xFF,
+ 0x61, 0xE3, 0x0F, 0xF0, 0xFF,
+ 0x61, 0xE4, 0x00, 0x00, 0x00,
+ 0x61, 0xE5, 0x00, 0x00, 0x00,
+ 0x61, 0xE5, 0x00, 0x00, 0x00,
+ 0x61, 0xE5, 0x00, 0x00, 0x00,
+ 0x61, 0xE6, 0x00, 0x00, 0x00,
+ 0x61, 0xE7, 0x00, 0x00, 0x00,
+ 0x61, 0xE7, 0x00, 0x00, 0x00,
+ 0x61, 0xE7, 0x00, 0x00, 0x00,
+ /* Padding */
+ 0, 0, 0, 0,
+ 0x61, 0xE0, 0x80, 0x00, 0x00,
+ 0x61,
+ 0xE1, 0x80, 0x00, 0x00,
+ 0x61, 0xE2, 0x80, 0x00, 0x00,
+ 0x61,
+ 0xE3, 0x80, 0x00, 0x00,
+ 0x61, 0xE4, 0x80, 0x00, 0x00,
+ 0x61,
+ 0xE5, 0x80, 0x00, 0x00,
+ 0x61, 0xE6, 0x80, 0x00, 0x00,
+ 0x61,
+ 0xE7, 0x80, 0x00, 0x00,
+/* More padding */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ currentMaterial.IndMtxAndScaleDL = new byte[] {
+ 0x61, 0x25, 0x00, 0x00, 0x00,
+ 0x61, 0x26, 0x00, 0x00, 0x00,
+ /* Padding */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ currentMaterial.TexCoordGenDL = new byte[] {
+ 0x10, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x52,
+ 0x80, 0x10,
+ 0x00, 0x00, 0x10, 0x50, 0x00, 0x00,
+/* Padding? */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CurrentModel.Materials.Add(parsed[1], currentMaterial);
+
+
+Shader thisShader = CreateShader();
+ CurrentModel.Shaders.Add(parsed[1], thisShader);
+ currentMaterial.ShaderRef = thisShader;
+
+ break;
+
+ case "map_Kd":
+ var rawTexName = string.Join(" ", parsed, 1, parsed.Length - 1);
+// TODO: fix this to use the mtllib path
+ var texPath = Path.Combine(BasePath, rawTexName);
+ var texName = Path.GetFileNameWithoutExtension(texPath);
+
+ if (!CurrentFile.GetTextureGroup().ContainsKey(texName))
+ AddTexture(texName, texPath);
+
+ var texInfo = new TextureInfo();
+ texInfo.TextureName = texName;
+
+ texInfo.WrapS = TextureWrapType.REPEAT;
+ texInfo.WrapT = TextureWrapType.REPEAT;
+
+ texInfo.MinFilt = 1;
+ texInfo.MagFilt = 1;
+
+ currentMaterial.TextureInfos.Add(texInfo);
+
+ break;
+
+
+ }
+ }
+ }
+
+
+ private void AddTexture(string texName, string texPath) {
+ var newTexture = new Texture();
+
+ newTexture.Images = new System.Drawing.Bitmap[1];
+ newTexture.Images[0] = new System.Drawing.Bitmap(texPath);
+
+ newTexture.Format = TextureFormat.RGB5A3;
+
+ CurrentFile.GetTextureGroup().Add(texName, newTexture);
+
+ // TODO: Texture/Material pairing lookups
+ }
+
+
+ private Shader CreateShader() {
+ var shader = new Shader();
+
+ shader.TevStageCount = 2;
+ shader.Unk1 = 0x00FFFFFF;
+ shader.Unk2 = 0xFFFFFFFF;
+ shader.DisplayList = new byte[] {
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xF6, 0x00, 0x00, 0x04,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xF7, 0x00, 0x00, 0x0E,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xF8, 0x00, 0x00, 0x00,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xF9, 0x00, 0x00, 0x0C,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xFA, 0x00, 0x00, 0x05,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xFB, 0x00, 0x00, 0x0D,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xFC, 0x00, 0x00, 0x0A,
+ 0x61, 0xFE, 0x00, 0x00, 0x0F,
+ 0x61, 0xFD, 0x00, 0x00, 0x0E,
+ 0x61, 0x27, 0xFF, 0xFF, 0xFF,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0x61, 0xFE, 0xFF, 0xFF,
+ 0xF0,
+ 0x61, 0xF6, 0xE3, 0x38, 0xC0,
+ 0x61, 0x28, 0x03, 0xF0,
+ 0x40,
+ 0x61, 0xC0, 0x08, 0xF8, 0xAF,
+ 0x61, 0xC2, 0x08, 0xF2,
+ 0x0F,
+ 0x61, 0xC1, 0x08, 0xF2, 0xF0,
+ 0x61, 0xC3, 0x08, 0x1F,
+ 0xF0,
+0x61, 0x10, 0x00, 0x00, 0x00,
+0x61, 0x11, 0x00, 0x00,
+ 0x00
+};
+
+ Array.Resize<byte>(ref shader.DisplayList, 0x1E0);
+
+ return shader;
+ }
+ #endregion
+
+
+
+ #region Shapes
+ Shape CurrentShape;
+ Material CurrentShapeMaterial;
+
+ List<ushort[]> Quads;
+ List<ushort[]> Triangles;
+
+ BitArray UsedVertices;
+ BitArray UsedNormals;
+ BitArray UsedTexCoords;
+
+ private void BeginShape(string name) {
+ if (CurrentShape != null)
+ EndShape();
+
+ CurrentShape = new Shape();
+ CurrentShape.Unk = new byte[] { 0, 0, 0x14, 0, 0, 0, 0, 0x02, 0,
+ 0, 0, 0x14 };
+ CurrentShape.DataFlags = 0x2600;
+ CurrentShape.ExtraData = new ushort[0];
+
+ CurrentModel.Shapes.Add(name, CurrentShape);
+
+ Quads = new List<ushort[]>();
+ Triangles = new List<ushort[]>();
+
+ UsedVertices = new BitArray(Positions.Count);
+ UsedTexCoords = new BitArray(TexCoords.Count);
+ UsedNormals = new BitArray(Normals.Count);
+ }
+
+
+ private void SetMaterial(Material mat) {
+ CurrentShapeMaterial = mat;
+ }
+
+
+ private void AddFace(string[] cmd) {
+ int vtxCount = cmd.Length - 1;
+ if (vtxCount != 3 && vtxCount != 4) {
+ throw new NotSupportedException(string.Format("cannot deal with a {0} vertices primitive", vtxCount));
+ }
+
+ var output = new ushort[vtxCount * 3];
+
+ for (int i = 0; i < vtxCount; i++) {
+ var s = cmd[i + 1];
+
+ int pos1 = s.IndexOf('/');
+ int pos2 = s.IndexOf('/', pos1 + 1);
+
+ int vnum = int.Parse(s.Substring(0, pos1)) - 1;
+ int tcnum = int.Parse(s.Substring(pos1 + 1, pos2 - pos1 - 1)) - 1;
+ int nnum = int.Parse(s.Substring(pos2 + 1)) - 1;
+
+ UsedVertices[vnum] = true;
+ UsedTexCoords[tcnum] = true;
+ UsedNormals[nnum] = true;
+
+ output[i * 3] = (ushort)vnum;
+ output[i * 3 + 1] = (ushort)nnum;
+ output[i * 3 + 2] = (ushort)tcnum;
+ }
+
+ if (vtxCount == 3)
+ Triangles.Add(output);
+ else
+ Quads.Add(output);
+ }
+
+
+ private void EndShape() {
+ // Let's assemble the display lists.
+
+ // ** Reverse Engineering DL 1 **
+ // 0x0A : CP command: Vertex Descriptor part 1
+ // 0x10 : CP command: Vertex Descriptor part 2
+ // 0x16 : XF command: Address 0x1008 ["XFMEM_VTXSPECS"], Transfer: 0
+ // 0x1F : Padding: NOP
+ // 0x20 : CP command: Vertex Attribute Format part 1
+ // 0x26 : CP command: Vertex Attribute Format part 2
+ // 0x2C : CP command: Vertex Attribute Format part 3
+ // 0x32 : Dynamic CP command: Position Array Pointer
+ // 0x38 : Dynamic CP command: Position Array Stride
+ // 0x3E : Dynamic CP command: Normal Array Pointer
+ // 0x44 : Dynamic CP command: Normal Array Pointer
+ // 0x4A : Dynamic CP command: Colour 0 Array Pointer
+ // 0x50 : Dynamic CP command: Colour 0 Array Stride
+ // 0x56 : Dynamic CP command: Colour 1 Array Pointer
+ // 0x5C : Dynamic CP command: Colour 1 Array Stride
+ // 0x62 : Dynamic CP command: TexCoord 0 Array Pointer
+ // 0x68 : Dynamic CP command: TexCoord 0 Array Stride
+ // 0x6E : Dynamic CP command: TexCoord 1 Array Pointer
+ // 0x74 : Dynamic CP command: TexCoord 1 Array Stride
+ // 0x7A : Dynamic CP command: TexCoord 2 Array Pointer
+ // 0x80 : Dynamic CP command: TexCoord 2 Array Stride
+ // 0x86 : Dynamic CP command: TexCoord 3 Array Pointer
+ // 0x8C : Dynamic CP command: TexCoord 3 Array Stride
+ // 0x92 : Dynamic CP command: TexCoord 4 Array Pointer
+ // 0x98 : Dynamic CP command: TexCoord 4 Array Stride
+ // 0x9E : Dynamic CP command: TexCoord 5 Array Pointer
+ // 0xA4 : Dynamic CP command: TexCoord 5 Array Stride
+ // 0xAA : Dynamic CP command: TexCoord 6 Array Pointer
+ // 0xB0 : Dynamic CP command: TexCoord 6 Array Stride
+ // 0xB6 : Dynamic CP command: TexCoord 7 Array Pointer
+ // 0xBC : Dynamic CP command: TexCoord 7 Array Stride
+
+ // Now create vertex settings
+ var vs = new VertexSettings();
+ vs.PositionDesc = VertexSettings.DescType.Index16;
+ vs.PositionFormat = VertexSettings.CompType.Float32;
+ vs.PositionCount = VertexSettings.CompCount.Position3;
+
+ vs.TexCoordDesc[0] = VertexSettings.DescType.Index16;
+ vs.TexCoordFormat[0] = VertexSettings.CompType.Float32;
+ vs.TexCoordCount[0] = VertexSettings.CompCount.TexCoord2;
+
+ vs.NormalDesc = VertexSettings.DescType.Index16;
+ vs.NormalFormat = VertexSettings.CompType.Float32;
+ vs.NormalCount = VertexSettings.CompCount.Normal3;
+
+ uint vd1, vd2, vat1, vat2, vat3;
+ vs.GetDesc(out vd1, out vd2);
+ vs.GetAttrFmt(out vat1, out vat2, out vat3);
+
+
+ // Todo: a Display List generator class
+
+ CurrentShape.DLBufferSize1 = 0xE0;
+ CurrentShape.DisplayList1 = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x08, 0x50,
+ (byte)((vd1 & 0xFF000000) >> 24),
+ (byte)((vd1 & 0x00FF0000) >> 16),
+ (byte)((vd1 & 0x0000FF00) >> 8),
+ (byte)((vd1 & 0x000000FF)),
+ 0x08, 0x60,
+ (byte)((vd2 & 0xFF000000) >> 24),
+ (byte)((vd2 & 0x00FF0000) >> 16),
+ (byte)((vd2 & 0x0000FF00) >> 8),
+ (byte)((vd2 & 0x000000FF)),
+ 0x10, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x14, 0,
+ 0x08, 0x70,
+ (byte)((vat1 & 0xFF000000) >> 24),
+ (byte)((vat1 & 0x00FF0000) >> 16),
+ (byte)((vat1 & 0x0000FF00) >> 8),
+ (byte)((vat1 & 0x000000FF)),
+ 0x08, 0x80,
+ (byte)((vat2 & 0xFF000000) >> 24),
+ (byte)((vat2 & 0x00FF0000) >> 16),
+ (byte)((vat2 & 0x0000FF00) >> 8),
+ (byte)((vat2 & 0x000000FF)),
+ 0x08, 0x90,
+ (byte)((vat3 & 0xFF000000) >> 24),
+ (byte)((vat3 & 0x00FF0000) >> 16),
+ (byte)((vat3 & 0x0000FF00) >> 8),
+ (byte)((vat3 & 0x000000FF))
+ };
+
+
+ // I might need to create XFMEM_VTXSPECS...
+ // test_lift uses 0x14. According to Dolphin's src, this means:
+ // numcolors = 0, numnormals = 1 (just normal), numtextures = 1. Makes sense.
+ byte vtxSpecs = 0 | (1 << 2) | (1 << 4);
+ CurrentShape.DisplayList1[0x1E] = vtxSpecs;
+
+ // extend it
+ // should it be bigger if more texcoords are used? maybe...
+ Array.Resize<byte>(ref CurrentShape.DisplayList1, 0x80);
+
+
+// Display List 2 is where all the primitive-related fun happens
+ // However, before we do that, let's compute the vertex data arrays
+ ushort[] posIndexes, texCoordIndexes, normalIndexes;
+
+ var posDataArray = ComputeVertexDataArray(Positions, UsedVertices, out posIndexes);
+ var tcDataArray = ComputeVertexDataArray(TexCoords, UsedTexCoords, out texCoordIndexes);
+ var nrmDataArray = ComputeVertexDataArray(Normals, UsedNormals, out normalIndexes);
+
+ // todo: better names
+ var posData = new VertexPosData();
+ posData.ComponentCount = VertexSettings.CompCount.Position3;
+ posData.ComponentType = VertexSettings.CompType.Float32;
+ posData.EntryCount = (ushort)posDataArray.Length;
+ posData.EntrySize = 12;
+ posData.Fraction = 0;
+ posData.Data = posDataArray;
+ posData.Save();
+
+ CurrentModel.VtxPosData.Add("Pos" + CurrentModel.VtxPosData.Count.ToString(), posData);
+
+ var tcData = new VertexTexCoordData();
+ tcData.ComponentCount = VertexSettings.CompCount.TexCoord2;
+ tcData.ComponentType = VertexSettings.CompType.Float32;
+ tcData.EntryCount = (ushort)tcDataArray.Length;
+ tcData.EntrySize = 8;
+ tcData.Fraction = 0;
+ tcData.Data = tcDataArray;
+ tcData.Save();
+
+ CurrentModel.VtxTexCoordData.Add("TexCoord" + CurrentModel.VtxTexCoordData.Count.ToString(), tcData);
+
+ // TODO: Flip texcoords
+
+ var nrmData = new VertexNrmData();
+ nrmData.ComponentCount = VertexSettings.CompCount.Normal3;
+ nrmData.ComponentType = VertexSettings.CompType.Float32;
+ nrmData.EntryCount = (ushort)nrmDataArray.Length;
+ nrmData.EntrySize = 12;
+ nrmData.Fraction = 0;
+ nrmData.Data = nrmDataArray;
+ nrmData.Save();
+
+ CurrentModel.VtxNrmData.Add("Nrm" + CurrentModel.VtxNrmData.Count.ToString(), nrmData);
+
+ CurrentShape.PosData = posData;
+ CurrentShape.TexCoordData[0] = tcData;
+ CurrentShape.NrmData = nrmData;
+
+ var dl = new OutputStream();
+
+ if (Triangles.Count > 0) {
+ dl.WriteByte((byte)GXCommand.DrawPrimitiveMask | ((byte)PrimitiveType.Triangles << (byte)GXCommand.PrimitiveShiftAmount));
+ dl.WriteUInt16((ushort)(Triangles.Count * 3));
+
+ foreach (var tri in Triangles) {
+ dl.WriteUInt16(posIndexes[tri[0]]);
+ dl.WriteUInt16(normalIndexes[tri[1]]);
+ dl.WriteUInt16(texCoordIndexes[tri[2]]);
+ dl.WriteUInt16(posIndexes[tri[3]]);
+ dl.WriteUInt16(normalIndexes[tri[4]]);
+ dl.WriteUInt16(texCoordIndexes[tri[5]]);
+ dl.WriteUInt16(posIndexes[tri[6]]);
+ dl.WriteUInt16(normalIndexes[tri[7]]);
+ dl.WriteUInt16(texCoordIndexes[tri[8]]);
+ }
+ }
+
+ if (Quads.Count > 0) {
+ dl.WriteByte((byte)GXCommand.DrawPrimitiveMask | ((byte)PrimitiveType.Quads << (byte)GXCommand.PrimitiveShiftAmount));
+ dl.WriteUInt16((ushort)(Quads.Count * 3));
+
+ foreach (var quad in Quads) {
+ dl.WriteUInt16(posIndexes[quad[0]]);
+ dl.WriteUInt16(normalIndexes[quad[1]]);
+ dl.WriteUInt16(texCoordIndexes[quad[2]]);
+ dl.WriteUInt16(posIndexes[quad[3]]);
+ dl.WriteUInt16(normalIndexes[quad[4]]);
+ dl.WriteUInt16(texCoordIndexes[quad[5]]);
+ dl.WriteUInt16(posIndexes[quad[6]]);
+ dl.WriteUInt16(normalIndexes[quad[7]]);
+ dl.WriteUInt16(texCoordIndexes[quad[8]]);
+ dl.WriteUInt16(posIndexes[quad[9]]);
+ dl.WriteUInt16(normalIndexes[quad[10]]);
+ dl.WriteUInt16(texCoordIndexes[quad[11]]);
+ }
+ }
+
+ dl.AlignTo(0x20);
+
+ CurrentShape.DisplayList2 = dl.GetBuffer();
+ CurrentShape.DLBufferSize2 = (uint)CurrentShape.DisplayList2.Length;
+
+ // now add it to DrawOpa
+ var newInsn = new ByteCode.DrawShapeInstruction();
+ newInsn.NodeID = 0;
+ newInsn.MaterialID = (ushort)CurrentModel.Materials.GetIndexForValue(CurrentShapeMaterial);
+ newInsn.ShapeID = (ushort)CurrentModel.Shapes.GetIndexForValue(CurrentShape);
+
+ CurrentModel.Bytecode["DrawOpa"].Instructions.Add(newInsn);
+ }
+
+
+
+ private float[][] ComputeVertexDataArray(List<float[]> objData, BitArray usedFields, out ushort[] indexes) {
+ indexes = new ushort[usedFields.Count];
+
+ var output = new List<float[]>();
+
+ // How this will work:
+ // I'll loop through every used vertex index in the BitArray.
+ // If it's used, I will compare it to the ones already in the output list.
+
+ // If the vertex is already in the output list, then I'll take the index of it
+ // and write it to the "indexes" array. If not, then I'll add it to the output list and do that.
+
+ // The "indexes" array matches input vertex indexes to the indexes in the optimised array.
+
+ int vertexCount = usedFields.Count;
+ int elementCount = objData[0].Length;
+
+ for (int i = 0; i < usedFields.Count; i++) {
+ if (usedFields[i]) {
+ // this one is used, let's try to find it
+ var thisVtx = objData[i];
+ bool foundIt = false;
+ int j;
+
+ for (j = 0; j < output.Count; j++) {
+ var check = output[j];
+ bool isEqual = true;
+ for (int k = 0; k < elementCount; k++)
+ isEqual &= (thisVtx[k] == check[k]);
+
+ if (isEqual) {
+ foundIt = true;
+ break;
+ }
+ }
+
+ if (foundIt) {
+ // it already exists, just add it to the indexes list
+ indexes[i] = (ushort)j;
+ } else {
+ // nope, add it to the computed list
+ indexes[i] = (ushort)output.Count;
+ output.Add(thisVtx);
+ }
+ }
+ }
+
+ return output.ToArray();
+ }
+ #endregion
+ }
+}
+
diff --git a/NW4RTools/ResFile.cs b/NW4RTools/ResFile.cs
index 02919e5..4f4a1b8 100644
--- a/NW4RTools/ResFile.cs
+++ b/NW4RTools/ResFile.cs
@@ -2,11 +2,46 @@ using System;
namespace NW4RTools {
public class ResFile : ResDict<object> {
+ public const string ModelGroupName = "3DModels(NW4R)";
+ public const string TextureGroupName = "Textures(NW4R)";
+
+
public UInt16 Version;
+ public ResDict<TValue> CreateGroup<TValue>(string name) {
+ if (ContainsKey(name)) {
+ return this[name] as ResDict<TValue>;
+ } else {
+ var newDict = new ResDict<TValue>();
+ this[name] = newDict;
+ return newDict;
+ }
+ }
+
public ResDict<TValue> GetGroup<TValue>(string name) {
return this[name] as ResDict<TValue>;
}
+
+
+ #region Specific Group Creators
+ public ResDict<Models.Model> CreateModelGroup() {
+ return CreateGroup<Models.Model>(ModelGroupName);
+ }
+
+ public ResDict<Texture> CreateTextureGroup() {
+ return CreateGroup<Texture>(TextureGroupName);
+ }
+ #endregion
+
+ #region Specific Group Getters
+ public ResDict<Models.Model> GetModelGroup() {
+ return GetGroup<Models.Model>(ModelGroupName);
+ }
+
+ public ResDict<Texture> GetTextureGroup() {
+ return GetGroup<Texture>(TextureGroupName);
+ }
+ #endregion
}
}
diff --git a/NW4RTools/Types.cs b/NW4RTools/Types.cs
index 78723dc..619303e 100644
--- a/NW4RTools/Types.cs
+++ b/NW4RTools/Types.cs
@@ -9,19 +9,65 @@ namespace NW4RTools {
public struct Color {
public byte r, g, b, a;
+
+ public uint Rgba {
+ get {
+ return ((uint)r << 24) | ((uint)g << 16) | ((uint)b << 8) | (uint)a;
+ }
+ set {
+ r = (byte)((value & 0xFF000000) >> 24);
+ g = (byte)((value & 0x00FF0000) >> 16);
+ b = (byte)((value & 0x0000FF00) >> 8);
+ a = (byte)(value & 0x000000FF);
+ }
+ }
+
+ public Color(byte _r, byte _g, byte _b, byte _a) {
+ r = _r;
+ g = _g;
+ b = _b;
+ a = _a;
+ }
}
public struct Vec3 {
public float x, y, z;
+
+ public Vec3(float _x, float _y, float _z) {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
}
public struct Vec2 {
public float x, y;
+
+ public Vec2(float _x, float _y) {
+ x = _x;
+ y = _y;
+ }
}
+ // TODO: Convert this to a packed struct, and change this[,] to use pointers
public struct Matrix {
public float v00, v01, v02, v03, v10, v11, v12, v13, v20, v21, v22, v23;
+ public void Identity() {
+ v00 = 1.0f;
+ v01 = 0.0f;
+ v02 = 0.0f;
+ v03 = 0.0f;
+ v10 = 0.0f;
+ v11 = 1.0f;
+ v12 = 0.0f;
+ v13 = 0.0f;
+ v20 = 0.0f;
+ v21 = 0.0f;
+ v22 = 1.0f;
+ v23 = 0.0f;
+ }
+
public float this[int x, int y] {
get {
switch (y) {
diff --git a/NW4RTools/VertexSettings.cs b/NW4RTools/VertexSettings.cs
index 2a0d3ac..4f05fd7 100644
--- a/NW4RTools/VertexSettings.cs
+++ b/NW4RTools/VertexSettings.cs
@@ -179,6 +179,23 @@ namespace NW4RTools {
}
+ public void GetDesc(out UInt32 val1, out UInt32 val2) {
+ val1 = 0;
+ val1 |= (uint)(PNMatrixIndexExists ? 1 : 0);
+
+ for (int i = 0; i < 8; i++)
+ val1 |= (TexCoordMatrixIndexExists[i] ? (uint)(2 << i) : 0);
+
+ val1 |= ((uint)PositionDesc) << 9;
+ val1 |= ((uint)NormalDesc) << 11;
+ val1 |= ((uint)ColorDesc[0]) << 13;
+ val1 |= ((uint)ColorDesc[1]) << 15;
+
+ val2 = 0;
+ for (int i = 0; i < 8; i++)
+ val2 |= ((uint)TexCoordDesc[i]) << (i * 2);
+ }
+
public void SetDesc(UInt32 val1, UInt32 val2) {
PNMatrixIndexExists = ((val1 & 1) != 0);
@@ -194,9 +211,69 @@ namespace NW4RTools {
TexCoordDesc[i] = (DescType)((val2 & (3 << (i * 2))) >> (i * 2));
}
+ public void GetAttrFmt(out UInt32 val1, out UInt32 val2, out UInt32 val3) {
+ val1 = 0;
+ val2 = 0;
+ val3 = 0;
+
+ val1 |= (uint)PositionCount;
+ val1 |= ((uint)PositionFormat) << 1;
+ val1 |= ((uint)PositionFrac) << 4;
+ if (PositionFrac > 0)
+ val1 |= 0x40000000;
+
+ val1 |= ((uint)NormalFormat) << 10;
+ if (NormalCount == VertexSettings.CompCount.NBT || NormalCount == VertexSettings.CompCount.NBT3)
+ val1 |= 0x200;
+ if (NormalCount == VertexSettings.CompCount.NBT3)
+ val1 |= 0x80000000;
+
+ val1 |= ((uint)ColorCount[0]) << 13;
+ val1 |= ((uint)ColorFormat[0]) << 14;
+ val1 |= ((uint)ColorCount[1]) << 17;
+ val1 |= ((uint)ColorFormat[1]) << 18;
+
+ for (int i = 0; i < 8; i++) {
+ if (TexCoordFrac[i] > 0)
+ val1 |= 0x40000000;
+ }
+
+ val1 |= ((uint)TexCoordCount[0]) << 21;
+ val1 |= ((uint)TexCoordFormat[0]) << 22;
+ val1 |= ((uint)TexCoordFrac[0]) << 25;
+
+ val2 |= ((uint)TexCoordCount[1]);
+ val2 |= ((uint)TexCoordFormat[1]) << 1;
+ val2 |= ((uint)TexCoordFrac[1]) << 4;
+
+ val2 |= ((uint)TexCoordCount[2]) << 9;
+ val2 |= ((uint)TexCoordFormat[2]) << 10;
+ val2 |= ((uint)TexCoordFrac[2]) << 13;
+
+ val2 |= ((uint)TexCoordCount[3]) << 18;
+ val2 |= ((uint)TexCoordFormat[3]) << 19;
+ val2 |= ((uint)TexCoordFrac[3]) << 22;
+
+ val2 |= ((uint)TexCoordCount[4]) << 27;
+ val2 |= ((uint)TexCoordFormat[4]) << 28;
+ val3 |= ((uint)TexCoordFrac[4]);
+
+ val3 |= ((uint)TexCoordCount[5]) << 5;
+ val3 |= ((uint)TexCoordFormat[5]) << 6;
+ val3 |= ((uint)TexCoordFrac[5]) << 9;
+
+ val3 |= ((uint)TexCoordCount[6]) << 14;
+ val3 |= ((uint)TexCoordFormat[6]) << 15;
+ val3 |= ((uint)TexCoordFrac[6]) << 18;
+
+ val3 |= ((uint)TexCoordCount[7]) << 23;
+ val3 |= ((uint)TexCoordFormat[7]) << 24;
+ val3 |= ((uint)TexCoordFrac[7]) << 27;
+ }
+
public void SetAttrFmt(UInt32 val1, UInt32 val2, UInt32 val3) {
PositionCount = (CompCount)(val1 & 1);
- PositionFormat = (CompType)((val1 & 0xE) >> 3);
+ PositionFormat = (CompType)((val1 & 0xE) >> 1);
PositionFrac = (byte)((val1 & 0x1F0) >> 4);
// note: this field is special
diff --git a/NW4RTools/bin/Debug/NW4RTools.dll b/NW4RTools/bin/Debug/NW4RTools.dll
index 1204c1d..e4c2ea1 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 badfeb7..62014b8 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 b9a8f13..a5db889 100644
--- a/TestApp/Main.cs
+++ b/TestApp/Main.cs
@@ -11,7 +11,7 @@ namespace TestApp {
public static void Main(string[] args) {
string mdlPath = "/home/me/Games/Newer/ModelRev/";
- //string mdlName = "CS_W1";
+ /*//string mdlName = "CS_W1";
//string mdlName = "bgB_4502";
//string mdlName = "cobKoopaCastle";
string mdlName = "waterPlate_W4boss";
@@ -22,7 +22,22 @@ namespace TestApp {
byte[] file = File.ReadAllBytes(mdlPath + mdlName + ".brres");
ResFile rf = BrresReader.LoadFile(file);
- File.WriteAllBytes(mdlPath + mdlName + "_rewritten.brres", BrresWriter.WriteFile(rf));
+ File.WriteAllBytes(mdlPath + mdlName + "_rewritten.brres", BrresWriter.WriteFile(rf));*/
+
+ // Going to create a model!
+ ResFile rf = new ResFile();
+
+ ObjImporter.ImportModel(mdlPath, File.OpenText(mdlPath + "crapmap.obj"), rf, "CrapMap");
+
+ File.WriteAllBytes(mdlPath + "crapmap.brres", BrresWriter.WriteFile(rf));
+
+
+ ResFile rf2 = BrresReader.LoadFile(File.ReadAllBytes(mdlPath + "crapmap.brres"));
+ using (var gw = new RenderWindow()) {
+ gw.Title = "crapmap";
+ gw.SetModel(rf2, "CrapMap");
+ gw.Run(1, 1);
+ }
/*using (var gw = new RenderWindow()) {
gw.Title = mdlName;
diff --git a/TestApp/RenderWindow.cs b/TestApp/RenderWindow.cs
index 3215190..2f29d0f 100644
--- a/TestApp/RenderWindow.cs
+++ b/TestApp/RenderWindow.cs
@@ -46,7 +46,7 @@ namespace TestApp {
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
//Matrix4 modelview = Matrix4.LookAt(new Vector3(1000, 600, 1000), new Vector3(1000, 0, 0), Vector3.UnitY);
- Matrix4 modelview = Matrix4.LookAt(new Vector3(0, 0, 1000), new Vector3(0, 0, 0), Vector3.UnitY);
+ Matrix4 modelview = Matrix4.LookAt(new Vector3(0, 2, 4), new Vector3(0, 0, 0), Vector3.UnitY);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
diff --git a/TestApp/TestApp.pidb b/TestApp/TestApp.pidb
index ad64e77..bbc694a 100644
--- a/TestApp/TestApp.pidb
+++ b/TestApp/TestApp.pidb
Binary files differ
diff --git a/TestApp/bin/Debug/NW4RTools.dll b/TestApp/bin/Debug/NW4RTools.dll
index aa8cfdd..e4c2ea1 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 02e5217..62014b8 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 d0238aa..a5251b0 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 2998706..7508ce0 100644
--- a/TestApp/bin/Debug/TestApp.exe.mdb
+++ b/TestApp/bin/Debug/TestApp.exe.mdb
Binary files differ