| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using System.IO; | 
 
 
 
 
 | 4 | using Oni.Imaging; | 
 
 
 
 
 | 5 |  | 
 
 
 
 
 | 6 | namespace Oni.Akira | 
 
 
 
 
 | 7 | { | 
 
 
 
 
 | 8 | internal class RoomDaeReader | 
 
 
 
 
 | 9 | { | 
 
 
 
 
 | 10 | private readonly PolygonMesh mesh; | 
 
 
 
 
 | 11 | private readonly List<Vector3> positions; | 
 
 
 
 
 | 12 | private readonly Stack<Matrix> nodeTransformStack; | 
 
 
 
 
 | 13 | private Dae.Scene scene; | 
 
 
 
 
 | 14 | private Matrix nodeTransform; | 
 
 
 
 
 | 15 |  | 
 
 
 
 
 | 16 | public static PolygonMesh Read(Dae.Scene scene) | 
 
 
 
 
 | 17 | { | 
 
 
 
 
 | 18 | var reader = new RoomDaeReader(); | 
 
 
 
 
 | 19 | reader.ReadScene(scene); | 
 
 
 
 
 | 20 | return reader.mesh; | 
 
 
 
 
 | 21 | } | 
 
 
 
 
 | 22 |  | 
 
 
 
 
 | 23 | private RoomDaeReader() | 
 
 
 
 
 | 24 | { | 
 
 
 
 
 | 25 | mesh = new PolygonMesh(new MaterialLibrary()); | 
 
 
 
 
 | 26 |  | 
 
 
 
 
 | 27 | positions = mesh.Points; | 
 
 
 
 
 | 28 |  | 
 
 
 
 
 | 29 | nodeTransformStack = new Stack<Matrix>(); | 
 
 
 
 
 | 30 | nodeTransform = Matrix.Identity; | 
 
 
 
 
 | 31 | } | 
 
 
 
 
 | 32 |  | 
 
 
 
 
 | 33 | private void ReadScene(Dae.Scene scene) | 
 
 
 
 
 | 34 | { | 
 
 
 
 
 | 35 | this.scene = scene; | 
 
 
 
 
 | 36 |  | 
 
 
 
 
 | 37 | foreach (Dae.Node node in scene.Nodes) | 
 
 
 
 
 | 38 | ReadNode(node); | 
 
 
 
 
 | 39 | } | 
 
 
 
 
 | 40 |  | 
 
 
 
 
 | 41 | private void ReadNode(Dae.Node node) | 
 
 
 
 
 | 42 | { | 
 
 
 
 
 | 43 | nodeTransformStack.Push(nodeTransform); | 
 
 
 
 
 | 44 |  | 
 
 
 
 
 | 45 | foreach (var transform in node.Transforms) | 
 
 
 
 
 | 46 | nodeTransform = transform.ToMatrix() * nodeTransform; | 
 
 
 
 
 | 47 |  | 
 
 
 
 
 | 48 | foreach (var geometryInstance in node.GeometryInstances) | 
 
 
 
 
 | 49 | ReadGeometryInstance(node, geometryInstance); | 
 
 
 
 
 | 50 |  | 
 
 
 
 
 | 51 | foreach (var child in node.Nodes) | 
 
 
 
 
 | 52 | ReadNode(child); | 
 
 
 
 
 | 53 |  | 
 
 
 
 
 | 54 | nodeTransform = nodeTransformStack.Pop(); | 
 
 
 
 
 | 55 | } | 
 
 
 
 
 | 56 |  | 
 
 
 
 
 | 57 | private void ReadGeometryInstance(Dae.Node node, Dae.GeometryInstance instance) | 
 
 
 
 
 | 58 | { | 
 
 
 
 
 | 59 | var geometry = instance.Target; | 
 
 
 
 
 | 60 |  | 
 
 
 
 
 | 61 | foreach (var primitives in geometry.Primitives) | 
 
 
 
 
 | 62 | { | 
 
 
 
 
 | 63 | if (primitives.PrimitiveType != Dae.MeshPrimitiveType.Polygons) | 
 
 
 
 
 | 64 | { | 
 
 
 
 
 | 65 | Console.Error.WriteLine("Unsupported primitive type '{0}' found in geometry '{1}', ignoring.", primitives.PrimitiveType, geometry.Id); | 
 
 
 
 
 | 66 | continue; | 
 
 
 
 
 | 67 | } | 
 
 
 
 
 | 68 |  | 
 
 
 
 
 | 69 | ReadPolygonPrimitives(node, primitives, instance.Materials.Find(m => m.Symbol == primitives.MaterialSymbol)); | 
 
 
 
 
 | 70 | } | 
 
 
 
 
 | 71 | } | 
 
 
 
 
 | 72 |  | 
 
 
 
 
 | 73 | private void ReadPolygonPrimitives(Dae.Node node, Dae.MeshPrimitives primitives, Dae.MaterialInstance materialInstance) | 
 
 
 
 
 | 74 | { | 
 
 
 
 
 | 75 | var positionInput = primitives.Inputs.FirstOrDefault(i => i.Semantic == Dae.Semantic.Position); | 
 
 
 
 
 | 76 | var positionIndices = ReadInputIndexed(positionInput, positions, Dae.Source.ReadVector3); | 
 
 
 
 
 | 77 |  | 
 
 
 
 
 | 78 | foreach (int i in positionIndices) | 
 
 
 
 
 | 79 | positions[i] = Vector3.Transform(positions[i], ref nodeTransform); | 
 
 
 
 
 | 80 |  | 
 
 
 
 
 | 81 | int startIndex = 0; | 
 
 
 
 
 | 82 |  | 
 
 
 
 
 | 83 | foreach (int vertexCount in primitives.VertexCounts) | 
 
 
 
 
 | 84 | { | 
 
 
 
 
 | 85 | var polygon = CreatePolygon(positionIndices, startIndex, vertexCount); | 
 
 
 
 
 | 86 | startIndex += vertexCount; | 
 
 
 
 
 | 87 |  | 
 
 
 
 
 | 88 | if (polygon == null) | 
 
 
 
 
 | 89 | { | 
 
 
 
 
 | 90 | Console.Error.WriteLine("BNV polygon: discarded, polygon is degenerate"); | 
 
 
 
 
 | 91 | continue; | 
 
 
 
 
 | 92 | } | 
 
 
 
 
 | 93 |  | 
 
 
 
 
 | 94 | polygon.FileName = node.FileName; | 
 
 
 
 
 | 95 | polygon.ObjectName = node.Name; | 
 
 
 
 
 | 96 |  | 
 
 
 
 
 | 97 | if (Math.Abs(polygon.Plane.Normal.Y) < 0.0001f) | 
 
 
 
 
 | 98 | { | 
 
 
 
 
 | 99 | if (polygon.BoundingBox.Height < 1.0f) | 
 
 
 
 
 | 100 | { | 
 
 
 
 
 | 101 | Console.Error.WriteLine("BNV polygon: discarded, ghost height must be greater than 1, it is {0}", polygon.BoundingBox.Height); | 
 
 
 
 
 | 102 | continue; | 
 
 
 
 
 | 103 | } | 
 
 
 
 
 | 104 |  | 
 
 
 
 
 | 105 | if (polygon.PointIndices.Length != 4) | 
 
 
 
 
 | 106 | { | 
 
 
 
 
 | 107 | Console.Error.WriteLine("BNV polygon: discarded, ghost is a {0}-gon", polygon.PointIndices.Length); | 
 
 
 
 
 | 108 | continue; | 
 
 
 
 
 | 109 | } | 
 
 
 
 
 | 110 |  | 
 
 
 
 
 | 111 | mesh.Ghosts.Add(polygon); | 
 
 
 
 
 | 112 | } | 
 
 
 
 
 | 113 | else if ((polygon.Flags & GunkFlags.Horizontal) != 0) | 
 
 
 
 
 | 114 | { | 
 
 
 
 
 | 115 | mesh.Floors.Add(polygon); | 
 
 
 
 
 | 116 | } | 
 
 
 
 
 | 117 | else | 
 
 
 
 
 | 118 | { | 
 
 
 
 
 | 119 | Console.Error.WriteLine("BNV polygon: discarded, not a ghost and not a floor"); | 
 
 
 
 
 | 120 | } | 
 
 
 
 
 | 121 | } | 
 
 
 
 
 | 122 | } | 
 
 
 
 
 | 123 |  | 
 
 
 
 
 | 124 | private Polygon CreatePolygon(int[] positionIndices, int startIndex, int vertexCount) | 
 
 
 
 
 | 125 | { | 
 
 
 
 
 | 126 | int endIndex = startIndex + vertexCount; | 
 
 
 
 
 | 127 |  | 
 
 
 
 
 | 128 | var indices = new List<int>(vertexCount); | 
 
 
 
 
 | 129 |  | 
 
 
 
 
 | 130 | for (int i = startIndex; i < endIndex; i++) | 
 
 
 
 
 | 131 | { | 
 
 
 
 
 | 132 | int i0 = positionIndices[i == startIndex ? endIndex - 1 : i - 1]; | 
 
 
 
 
 | 133 | int i1 = positionIndices[i]; | 
 
 
 
 
 | 134 | int i2 = positionIndices[i + 1 == endIndex ? startIndex : i + 1]; | 
 
 
 
 
 | 135 |  | 
 
 
 
 
 | 136 | if (i0 == i1) | 
 
 
 
 
 | 137 | { | 
 
 
 
 
 | 138 | Console.Error.WriteLine("BNV polygon: discarding degenerate edge {0}", mesh.Points[i1]); | 
 
 
 
 
 | 139 | continue; | 
 
 
 
 
 | 140 | } | 
 
 
 
 
 | 141 |  | 
 
 
 
 
 | 142 | Vector3 p0 = mesh.Points[i0]; | 
 
 
 
 
 | 143 | Vector3 p1 = mesh.Points[i1]; | 
 
 
 
 
 | 144 | Vector3 p2 = mesh.Points[i2]; | 
 
 
 
 
 | 145 |  | 
 
 
 
 
 | 146 | Vector3 p1p0 = p1 - p0; | 
 
 
 
 
 | 147 | Vector3 p2p1 = p2 - p1; | 
 
 
 
 
 | 148 |  | 
 
 
 
 
 | 149 | //if (p1p0.LengthSquared() < 0.000001f) | 
 
 
 
 
 | 150 | //{ | 
 
 
 
 
 | 151 | //    Console.Error.WriteLine("BNV polygon: merging duplicate points {0} {1}", p0, p1); | 
 
 
 
 
 | 152 | //    continue; | 
 
 
 
 
 | 153 | //} | 
 
 
 
 
 | 154 |  | 
 
 
 
 
 | 155 | if (Vector3.Cross(p2p1, p1p0).LengthSquared() < 0.000001f) | 
 
 
 
 
 | 156 | { | 
 
 
 
 
 | 157 | //Console.Error.WriteLine("BNV polygon: combining colinear edges at {0}", p1); | 
 
 
 
 
 | 158 | continue; | 
 
 
 
 
 | 159 | } | 
 
 
 
 
 | 160 |  | 
 
 
 
 
 | 161 | indices.Add(i1); | 
 
 
 
 
 | 162 | } | 
 
 
 
 
 | 163 |  | 
 
 
 
 
 | 164 | var indicesArray = indices.ToArray(); | 
 
 
 
 
 | 165 |  | 
 
 
 
 
 | 166 | if (CheckDegenerate(mesh.Points, indicesArray)) | 
 
 
 
 
 | 167 | return null; | 
 
 
 
 
 | 168 |  | 
 
 
 
 
 | 169 | return new Polygon(mesh, indicesArray); | 
 
 
 
 
 | 170 | } | 
 
 
 
 
 | 171 |  | 
 
 
 
 
 | 172 | private static bool CheckDegenerate(List<Vector3> positions, int[] indices) | 
 
 
 
 
 | 173 | { | 
 
 
 
 
 | 174 | if (indices.Length < 3) | 
 
 
 
 
 | 175 | return true; | 
 
 
 
 
 | 176 |  | 
 
 
 
 
 | 177 | Vector3 p0 = positions[indices[0]]; | 
 
 
 
 
 | 178 | Vector3 p1 = positions[indices[1]]; | 
 
 
 
 
 | 179 | Vector3 s0, s1, c; | 
 
 
 
 
 | 180 |  | 
 
 
 
 
 | 181 | for (int i = 2; i < indices.Length; i++) | 
 
 
 
 
 | 182 | { | 
 
 
 
 
 | 183 | Vector3 p2 = positions[indices[i]]; | 
 
 
 
 
 | 184 |  | 
 
 
 
 
 | 185 | Vector3.Substract(ref p0, ref p1, out s0); | 
 
 
 
 
 | 186 | Vector3.Substract(ref p2, ref p1, out s1); | 
 
 
 
 
 | 187 | Vector3.Cross(ref s0, ref s1, out c); | 
 
 
 
 
 | 188 |  | 
 
 
 
 
 | 189 | if (Math.Abs(c.LengthSquared()) < 0.0001f && Vector3.Dot(ref s0, ref s1) > 0.0f) | 
 
 
 
 
 | 190 | return true; | 
 
 
 
 
 | 191 |  | 
 
 
 
 
 | 192 | p0 = p1; | 
 
 
 
 
 | 193 | p1 = p2; | 
 
 
 
 
 | 194 | } | 
 
 
 
 
 | 195 |  | 
 
 
 
 
 | 196 | return false; | 
 
 
 
 
 | 197 | } | 
 
 
 
 
 | 198 |  | 
 
 
 
 
 | 199 | private static int[] ReadInputIndexed<T>(Dae.IndexedInput input, List<T> list, Func<Dae.Source, int, T> elementReader) | 
 
 
 
 
 | 200 | where T : struct | 
 
 
 
 
 | 201 | { | 
 
 
 
 
 | 202 | var indices = new int[input.Indices.Count]; | 
 
 
 
 
 | 203 |  | 
 
 
 
 
 | 204 | for (int i = 0; i < input.Indices.Count; i++) | 
 
 
 
 
 | 205 | { | 
 
 
 
 
 | 206 | var v = elementReader(input.Source, input.Indices[i]); | 
 
 
 
 
 | 207 | indices[i] = list.Count; | 
 
 
 
 
 | 208 | list.Add(v); | 
 
 
 
 
 | 209 | } | 
 
 
 
 
 | 210 |  | 
 
 
 
 
 | 211 | return indices; | 
 
 
 
 
 | 212 | } | 
 
 
 
 
 | 213 | } | 
 
 
 
 
 | 214 | } |