summaryrefslogtreecommitdiff
path: root/NW4RTools/ObjImporter.cs
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-03-19 05:17:37 +0100
committerTreeki <treeki@gmail.com>2011-03-19 05:17:37 +0100
commit6893a74fad0c58fceda13088bd5bd585950931b9 (patch)
tree055cc31703723c0f8c49121e8b1c532aaa46e6b4 /NW4RTools/ObjImporter.cs
parentb625da59b0bbe60a9380dbd00df1ae982e6b5a58 (diff)
downloadnw4rtools-6893a74fad0c58fceda13088bd5bd585950931b9.tar.gz
nw4rtools-6893a74fad0c58fceda13088bd5bd585950931b9.zip
support for .obj groups which use multiple materials ... but it's broken :(
Diffstat (limited to '')
-rwxr-xr-xNW4RTools/ObjImporter.cs189
1 files changed, 109 insertions, 80 deletions
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<float[]> Normals;
List<float[]> 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<ushort[]> Quads;
+ public List<ushort[]> Triangles;
+
+ public BitArray UsedVertices;
+ public BitArray UsedNormals;
+ public BitArray UsedTexCoords;
}
+ ShapeContext CurrentShape;
+
+ Util.OrderedDictionary<string, ShapeContext> 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<string, ShapeContext>();
+
// 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<float[]>();
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<ushort[]> Quads;
- List<ushort[]> 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<ushort[]>();
- Triangles = new List<ushort[]>();
- 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<ushort[]>();
+ context.Triangles = new List<ushort[]>();
- 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<float[]> objData, BitArray usedFields, out ushort[] indexes) {
+ private static float[][] ComputeVertexDataArray(List<float[]> objData, BitArray usedFields, out ushort[] indexes) {
indexes = new ushort[usedFields.Count];
var output = new List<float[]>();