using System; using System.Collections.Generic; namespace Oni.Motoko { internal static class GeometryDatReader { public static Geometry Read(InstanceDescriptor m3gm) { if (m3gm.Template.Tag != TemplateTag.M3GM) throw new ArgumentException(string.Format("Invalid instance type {0}", m3gm.Template.Tag), "m3gm"); InstanceDescriptor pnta; InstanceDescriptor vcra1; InstanceDescriptor vcra2; InstanceDescriptor txca; InstanceDescriptor idxa1; InstanceDescriptor idxa2; InstanceDescriptor txmp; using (var reader = m3gm.OpenRead(4)) { pnta = reader.ReadInstance(); vcra1 = reader.ReadInstance(); vcra2 = reader.ReadInstance(); txca = reader.ReadInstance(); idxa1 = reader.ReadInstance(); idxa2 = reader.ReadInstance(); txmp = reader.ReadInstance(); } var geometry = new Geometry { Name = m3gm.FullName, Texture = txmp }; Vector3[] faceNormals; int[] faceIndices; int[] vertexIndices; using (var reader = pnta.OpenRead(52)) geometry.Points = reader.ReadVector3Array(reader.ReadInt32()); using (var reader = vcra1.OpenRead(20)) geometry.Normals = reader.ReadVector3Array(reader.ReadInt32()); using (var reader = vcra2.OpenRead(20)) faceNormals = reader.ReadVector3Array(reader.ReadInt32()); using (var reader = txca.OpenRead(20)) geometry.TexCoords = reader.ReadVector2Array(reader.ReadInt32()); using (var reader = idxa1.OpenRead(20)) vertexIndices = reader.ReadInt32Array(reader.ReadInt32()); using (var reader = idxa2.OpenRead(20)) faceIndices = reader.ReadInt32Array(reader.ReadInt32()); geometry.Triangles = ConvertTriangleStripToTriangleList(geometry.Points, vertexIndices, faceNormals, faceIndices); return geometry; } private static int[] ConvertTriangleStripToTriangleList(Vector3[] points, int[] vIndices, Vector3[] fNormals, int[] fIndices) { var triangles = new List(vIndices.Length * 2); var face = new int[3]; int faceIndex = 0; int order = 0; for (int i = 0; i < vIndices.Length; i++) { if (vIndices[i] < 0) { face[0] = vIndices[i++] & int.MaxValue; face[1] = vIndices[i++]; order = 0; } else { face[order] = face[2]; order ^= 1; } face[2] = vIndices[i]; var v1 = points[face[0]]; var v2 = points[face[1]]; var v3 = points[face[2]]; var faceNormal1 = Vector3.Normalize(fNormals[fIndices[faceIndex]]); var faceNormal2 = Vector3.Normalize(Vector3.Cross(v2 - v1, v3 - v1)); if (Vector3.Dot(faceNormal1, faceNormal2) < 0.0f) { triangles.Add(face[2]); triangles.Add(face[1]); triangles.Add(face[0]); } else { triangles.Add(face[0]); triangles.Add(face[1]); triangles.Add(face[2]); } faceIndex++; } return triangles.ToArray(); } } }