using System; using System.Collections.Generic; namespace Oni.Motoko { internal class GeometryDaeWriter { private readonly TextureDaeWriter textureWriter; public GeometryDaeWriter(TextureDaeWriter textureWriter) { this.textureWriter = textureWriter; } public Dae.Node WriteNode(Geometry geometry, string name) { var daeGeometryInstance = WriteGeometryInstance(geometry, name); return new Dae.Node { Name = name, Instances = { daeGeometryInstance } }; } public Dae.GeometryInstance WriteGeometryInstance(Geometry geometry, string name) { var daeGeometry = WriteGeometry(geometry, name); var daeGeometryInstance = new Dae.GeometryInstance(daeGeometry); if (geometry.Texture != null) { var daeMaterial = textureWriter.WriteMaterial(geometry.Texture); daeGeometryInstance.Materials.Add(new Dae.MaterialInstance("default", daeMaterial) { Bindings = { new Dae.MaterialBinding( semantic: "diffuse_TEXCOORD", input: daeGeometry.Primitives[0].Inputs.Find(i => i.Semantic == Dae.Semantic.TexCoord)) } }); } return daeGeometryInstance; } private Dae.Geometry WriteGeometry(Geometry geometry, string name) { var points = geometry.Points; var normals = geometry.Normals; var texCoords = geometry.TexCoords; if (geometry.HasTransform) { points = Vector3.Transform(points, ref geometry.Transform); normals = Vector3.TransformNormal(normals, ref geometry.Transform); } int[] pointMap; points = WeldPoints(points, out pointMap); var positionInput = new Dae.IndexedInput(Dae.Semantic.Position, new Dae.Source(points)); var normalInput = new Dae.IndexedInput(Dae.Semantic.Normal, new Dae.Source(normals)); var texCoordInput = new Dae.IndexedInput(Dae.Semantic.TexCoord, new Dae.Source(texCoords)); var primitives = new Dae.MeshPrimitives(Dae.MeshPrimitiveType.Polygons) { MaterialSymbol = "default", Inputs = { positionInput, normalInput, texCoordInput } }; for (int triangleStart = 0; triangleStart < geometry.Triangles.Length; triangleStart += 3) { primitives.VertexCounts.Add(3); for (int i = 0; i < 3; i++) { int index = geometry.Triangles[triangleStart + i]; positionInput.Indices.Add(pointMap[index]); texCoordInput.Indices.Add(index); normalInput.Indices.Add(index); } } return new Dae.Geometry { Name = name, Vertices = { positionInput }, Primitives = { primitives } }; } private static T[] WeldPoints(T[] list, out int[] map) { var indicesMap = new int[list.Length]; var index = new Dictionary(list.Length); var result = new List(list.Length); for (int i = 0; i < indicesMap.Length; i++) { var v = list[i]; if (!index.TryGetValue(v, out indicesMap[i])) { indicesMap[i] = result.Count; result.Add(v); index.Add(v, indicesMap[i]); } } map = indicesMap; return result.ToArray(); } } }