From 6893a74fad0c58fceda13088bd5bd585950931b9 Mon Sep 17 00:00:00 2001 From: Treeki Date: Sat, 19 Mar 2011 05:17:37 +0100 Subject: support for .obj groups which use multiple materials ... but it's broken :( --- NW4RTools.userprefs | 4 +- NW4RTools/NW4RTools.pidb | Bin 583120 -> 583120 bytes NW4RTools/ObjImporter.cs | 189 ++++++++++++++++++++-------------- NW4RTools/bin/Debug/NW4RTools.dll | Bin 237568 -> 237568 bytes NW4RTools/bin/Debug/NW4RTools.dll.mdb | Bin 114410 -> 114593 bytes TestApp/Main.cs | 2 +- TestApp/TestApp.pidb | Bin 4427 -> 4427 bytes TestApp/bin/Debug/NW4RTools.dll | Bin 237568 -> 237568 bytes TestApp/bin/Debug/NW4RTools.dll.mdb | Bin 114410 -> 114593 bytes TestApp/bin/Debug/TestApp.exe | Bin 7680 -> 7680 bytes TestApp/bin/Debug/TestApp.exe.mdb | Bin 1300 -> 1300 bytes 11 files changed, 112 insertions(+), 83 deletions(-) diff --git a/NW4RTools.userprefs b/NW4RTools.userprefs index 23a624e..9212cb2 100644 --- a/NW4RTools.userprefs +++ b/NW4RTools.userprefs @@ -2,13 +2,13 @@ - + - + diff --git a/NW4RTools/NW4RTools.pidb b/NW4RTools/NW4RTools.pidb index 9cf16d4..4d2cd3b 100644 Binary files a/NW4RTools/NW4RTools.pidb and b/NW4RTools/NW4RTools.pidb differ diff --git a/NW4RTools/ObjImporter.cs b/NW4RTools/ObjImporter.cs index 5410227..7dfe043 100755 --- a/NW4RTools/ObjImporter.cs +++ b/NW4RTools/ObjImporter.cs @@ -22,6 +22,12 @@ namespace NW4RTools { + private ObjImporter(string basePath, ResFile file, TextReader tr) { + BasePath = basePath; + CurrentFile = file; + Input = tr; + } + LightmapType Lightmap; string LightmapName1, LightmapName2; @@ -35,12 +41,25 @@ namespace NW4RTools { List Normals; List TexCoords; - private ObjImporter(string basePath, ResFile file, TextReader tr) { - BasePath = basePath; - CurrentFile = file; - Input = tr; + + + class ShapeContext { + public Shape Shape; + public Material Material; + + public List Quads; + public List Triangles; + + public BitArray UsedVertices; + public BitArray UsedNormals; + public BitArray UsedTexCoords; } + ShapeContext CurrentShape; + + Util.OrderedDictionary KnownShapes; + + public void ImportModel(string modelName, LightmapType lmt) { var modelGroup = CurrentFile.CreateModelGroup(); var texGroup = CurrentFile.CreateTextureGroup(); @@ -59,22 +78,30 @@ namespace NW4RTools { // 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. + // One Shape will be created for each group and material pair. + // I'll make the assumption that a "g" command will ALWAYS be followed by a "usemtl" command. + + KnownShapes = new Util.OrderedDictionary(); + // 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. + // -- These will be added into a list for the current Shape. // Set group (g): - // -- A shape will be created for this group. It will be added to DrawOpa. - // -- TODO: Add DrawXlu handling. + // -- It will be stored as the current group name. // 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. + // -- The current Shape will be changed. + // -- If a Shape already exists for this material AND the current group, then it will become the current + // Shape. Otherwise, a new one will be created. + + // At the end of the .obj parsing, all the shapes will be converted and written. if (Lightmap != LightmapType.None && !texGroup.ContainsKey(LightmapName1)) { var lm01 = new Texture(); @@ -117,20 +144,9 @@ namespace NW4RTools { 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.NodeMatrix.Identity(); + newNode.NodeInvMatrix.v00 = 1; newNode.NodeInvMatrix.v01 = -0; newNode.NodeInvMatrix.v02 = 0; @@ -173,6 +189,7 @@ namespace NW4RTools { TexCoords = new List(); string line; + string currentGroup = null; while ((line = Input.ReadLine()) != null) { line = line.Trim(); @@ -217,12 +234,12 @@ namespace NW4RTools { AddFace(parsed); break; case "g": - Console.WriteLine("Beginning shape {0}", parsed[1]); - BeginShape(parsed[1]); + Console.WriteLine("Current group is now {0}", parsed[1]); + currentGroup = parsed[1]; break; case "usemtl": - Console.WriteLine("Setting material {0}", parsed[1]); - SetMaterial(CurrentModel.Materials[parsed[1]]); + Console.WriteLine("Current material is now {0}", parsed[1]); + SetCurrentShape(currentGroup, parsed[1]); break; default: Console.WriteLine("Unhandled OBJ command: {0}", parsed[0]); @@ -230,9 +247,11 @@ namespace NW4RTools { } } - EndShape(); + // Parsing is finished. Let's convert every shape and finish up DrawOpa! + foreach (var pair in KnownShapes) { + FinaliseShape(pair.Value); + } - // Parsing is finished. Let's finish up DrawOpa drawOpa.Instructions.Add(new ByteCode.DoneInstruction()); CurrentModel.Minimum = minimum; @@ -240,11 +259,11 @@ namespace NW4RTools { } - private float[] ParseFloatArray(string[] src, int index) { + private static float[] ParseFloatArray(string[] src, int index) { return ParseFloatArray(src, index, src.Length - index); } - private float[] ParseFloatArray(string[] src, int index, int count) { + private static float[] ParseFloatArray(string[] src, int index, int count) { var output = new float[count]; for (int i = 0; i < count; i++) { @@ -602,39 +621,42 @@ namespace NW4RTools { #region Shapes - Shape CurrentShape; - Material CurrentShapeMaterial; + private void SetCurrentShape(string groupName, string materialName) { + string shapeName = groupName + "__" + materialName; - List Quads; - List Triangles; + if (KnownShapes.ContainsKey(shapeName)) { + CurrentShape = KnownShapes[shapeName]; + } else { + // make a new one! + var context = MakeNewShapeContext(shapeName, CurrentModel.Materials[materialName]); + KnownShapes[shapeName] = context; + CurrentShape = context; + } + } - BitArray UsedVertices; - BitArray UsedNormals; - BitArray UsedTexCoords; - private void BeginShape(string name) { - if (CurrentShape != null) - EndShape(); + private ShapeContext MakeNewShapeContext(string name, Material material) { + var context = new ShapeContext(); - 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]; + var shape = new Shape(); + shape.Unk = new byte[] { 0, 0, 0x14, 0, 0, 0, 0, 0x02, 0, 0, 0, 0x14 }; + shape.DataFlags = 0x2600; + shape.ExtraData = new ushort[0]; - CurrentModel.Shapes.Add(name, CurrentShape); + CurrentModel.Shapes.Add(name, shape); - Quads = new List(); - Triangles = new List(); - UsedVertices = new BitArray(Positions.Count); - UsedTexCoords = new BitArray(TexCoords.Count); - UsedNormals = new BitArray(Normals.Count); - } + context.Shape = shape; + context.Material = material; + context.Quads = new List(); + context.Triangles = new List(); - private void SetMaterial(Material mat) { - CurrentShapeMaterial = mat; + context.UsedVertices = new BitArray(Positions.Count); + context.UsedTexCoords = new BitArray(TexCoords.Count); + context.UsedNormals = new BitArray(Normals.Count); + + return context; } @@ -659,10 +681,10 @@ namespace NW4RTools { int tcnum = hasTexCoord ? (int.Parse(s.Substring(pos1 + 1, pos2 - pos1 - 1)) - 1) : 0; int nnum = int.Parse(s.Substring(pos2 + 1)) - 1; - UsedVertices[vnum] = true; + CurrentShape.UsedVertices[vnum] = true; if (hasTexCoord) - UsedTexCoords[tcnum] = true; - UsedNormals[nnum] = true; + CurrentShape.UsedTexCoords[tcnum] = true; + CurrentShape.UsedNormals[nnum] = true; output[i * 3] = (ushort)vnum; output[i * 3 + 1] = (ushort)nnum; @@ -670,22 +692,24 @@ namespace NW4RTools { } if (vtxCount == 3) - Triangles.Add(output); + CurrentShape.Triangles.Add(output); else - Quads.Add(output); + CurrentShape.Quads.Add(output); } - private void EndShape() { + private void FinaliseShape(ShapeContext context) { + var shape = context.Shape; + // Let's assemble the display lists. // First off, compute the vertex data arrays so we can decide on whether // to use 8-bit or 16-bit indexes to vertex data 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); + var posDataArray = ComputeVertexDataArray(Positions, context.UsedVertices, out posIndexes); + var tcDataArray = ComputeVertexDataArray(TexCoords, context.UsedTexCoords, out texCoordIndexes); + var nrmDataArray = ComputeVertexDataArray(Normals, context.UsedNormals, out normalIndexes); bool u16PosIdx = (posDataArray.Length > 255); bool u16TcIdx = (tcDataArray.Length > 255); @@ -776,8 +800,8 @@ namespace NW4RTools { dl1.PadToSize(0x80); dl1.End(); - CurrentShape.DLBufferSize1 = 0xE0; - CurrentShape.DisplayList1 = dl1.GetBuffer(); + shape.DLBufferSize1 = 0xE0; + shape.DisplayList1 = dl1.GetBuffer(); // Display List 2 is where all the primitive-related fun happens @@ -793,11 +817,16 @@ namespace NW4RTools { posData.Data = posDataArray; posData.Save(); - CurrentShape.PosData = posData; + shape.PosData = posData; CurrentModel.VtxPosData.Add("P_" + CurrentModel.VtxPosData.Count.ToString(), posData); var tcData = new VertexTexCoordData(); + // a Quick Hack + if (tcDataArray.Length == 0) { + tcDataArray = new float[][] { new float[] { 0, 0 } }; + } + tcData.ComponentCount = VertexSettings.CompCount.TexCoord2; tcData.ComponentType = VertexSettings.CompType.Float32; tcData.EntryCount = (ushort)tcDataArray.Length; @@ -806,7 +835,7 @@ namespace NW4RTools { tcData.Data = tcDataArray; tcData.Save(); - CurrentShape.TexCoordData[0] = tcData; + shape.TexCoordData[0] = tcData; CurrentModel.VtxTexCoordData.Add("T_" + CurrentModel.VtxTexCoordData.Count.ToString(), tcData); var nrmData = new VertexNrmData(); @@ -818,7 +847,7 @@ namespace NW4RTools { nrmData.Data = nrmDataArray; nrmData.Save(); - CurrentShape.NrmData = nrmData; + shape.NrmData = nrmData; CurrentModel.VtxNrmData.Add("N_" + CurrentModel.VtxNrmData.Count.ToString(), nrmData); // For lightmaps, before we get baked lighting working @@ -832,7 +861,7 @@ namespace NW4RTools { clrData.RawData = new byte[] { 255, 255, 255, 255 }; CurrentModel.VtxClrData.Add("C_" + CurrentModel.VtxClrData.Count.ToString(), clrData); - CurrentShape.ClrData[0] = clrData; + shape.ClrData[0] = clrData; } @@ -844,10 +873,10 @@ namespace NW4RTools { // 0 bytes are for colour indexes - if (Triangles.Count > 0) { - dl.BeginPrimitives(PrimitiveType.Triangles, 0, (ushort)(Triangles.Count * 3)); + if (context.Triangles.Count > 0) { + dl.BeginPrimitives(PrimitiveType.Triangles, 0, (ushort)(context.Triangles.Count * 3)); - foreach (var tri in Triangles) { + foreach (var tri in context.Triangles) { if (u16PosIdx) dl.WriteUInt16(posIndexes[tri[6]]); else @@ -895,10 +924,10 @@ namespace NW4RTools { } } - if (Quads.Count > 0) { - dl.BeginPrimitives(PrimitiveType.Quads, 0, (ushort)(Quads.Count * 4)); + if (context.Quads.Count > 0) { + dl.BeginPrimitives(PrimitiveType.Quads, 0, (ushort)(context.Quads.Count * 4)); - foreach (var quad in Quads) { + foreach (var quad in context.Quads) { if (u16PosIdx) dl.WriteUInt16(posIndexes[quad[9]]); else @@ -963,21 +992,21 @@ namespace NW4RTools { dl.End(); - CurrentShape.DisplayList2 = dl.GetBuffer(); - CurrentShape.DLBufferSize2 = (uint)CurrentShape.DisplayList2.Length; + shape.DisplayList2 = dl.GetBuffer(); + shape.DLBufferSize2 = (uint)shape.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); + newInsn.MaterialID = (ushort)CurrentModel.Materials.GetIndexForValue(context.Material); + newInsn.ShapeID = (ushort)CurrentModel.Shapes.GetIndexForValue(shape); CurrentModel.Bytecode["DrawOpa"].Instructions.Add(newInsn); } - private float[][] ComputeVertexDataArray(List objData, BitArray usedFields, out ushort[] indexes) { + private static float[][] ComputeVertexDataArray(List objData, BitArray usedFields, out ushort[] indexes) { indexes = new ushort[usedFields.Count]; var output = new List(); diff --git a/NW4RTools/bin/Debug/NW4RTools.dll b/NW4RTools/bin/Debug/NW4RTools.dll index 6cd7365..0f298cf 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 208c344..c7a54e3 100644 Binary files a/NW4RTools/bin/Debug/NW4RTools.dll.mdb and b/NW4RTools/bin/Debug/NW4RTools.dll.mdb differ diff --git a/TestApp/Main.cs b/TestApp/Main.cs index 71b577b..4901ec4 100644 --- a/TestApp/Main.cs +++ b/TestApp/Main.cs @@ -33,7 +33,7 @@ namespace TestApp { ResFile rf = new ResFile(); - ObjImporter.ImportModel(mdlPath, File.OpenText(mdlPath + "fullworld-Z6-fail.obj"), rf, resmdlname, ObjImporter.LightmapType.Map); + ObjImporter.ImportModel(mdlPath, File.OpenText(mdlPath + "fullworld-tree-fbx.obj"), rf, resmdlname, ObjImporter.LightmapType.Map); File.WriteAllBytes(mdlPath + filename + ".brres", BrresWriter.WriteFile(rf)); diff --git a/TestApp/TestApp.pidb b/TestApp/TestApp.pidb index af45428..5bfaccd 100644 Binary files a/TestApp/TestApp.pidb and b/TestApp/TestApp.pidb differ diff --git a/TestApp/bin/Debug/NW4RTools.dll b/TestApp/bin/Debug/NW4RTools.dll index 6cd7365..0f298cf 100755 Binary files a/TestApp/bin/Debug/NW4RTools.dll and b/TestApp/bin/Debug/NW4RTools.dll differ diff --git a/TestApp/bin/Debug/NW4RTools.dll.mdb b/TestApp/bin/Debug/NW4RTools.dll.mdb index 208c344..c7a54e3 100644 Binary files a/TestApp/bin/Debug/NW4RTools.dll.mdb and b/TestApp/bin/Debug/NW4RTools.dll.mdb differ diff --git a/TestApp/bin/Debug/TestApp.exe b/TestApp/bin/Debug/TestApp.exe index ee143e2..637548b 100755 Binary files a/TestApp/bin/Debug/TestApp.exe and b/TestApp/bin/Debug/TestApp.exe differ diff --git a/TestApp/bin/Debug/TestApp.exe.mdb b/TestApp/bin/Debug/TestApp.exe.mdb index b46c061..4b7be18 100644 Binary files a/TestApp/bin/Debug/TestApp.exe.mdb and b/TestApp/bin/Debug/TestApp.exe.mdb differ -- cgit v1.2.3