| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using Oni.Collections; | 
 
 
 
 
 | 4 |  | 
 
 
 
 
 | 5 | namespace Oni.Dae | 
 
 
 
 
 | 6 | { | 
 
 
 
 
 | 7 | internal class FaceConverter | 
 
 
 
 
 | 8 | { | 
 
 
 
 
 | 9 | private Node root; | 
 
 
 
 
 | 10 | private int maxEdges = 3; | 
 
 
 
 
 | 11 |  | 
 
 
 
 
 | 12 | public static void Triangulate(Node root) | 
 
 
 
 
 | 13 | { | 
 
 
 
 
 | 14 | var converter = new FaceConverter { | 
 
 
 
 
 | 15 | root = root | 
 
 
 
 
 | 16 | }; | 
 
 
 
 
 | 17 |  | 
 
 
 
 
 | 18 | converter.Convert(); | 
 
 
 
 
 | 19 | } | 
 
 
 
 
 | 20 |  | 
 
 
 
 
 | 21 | private void Convert() | 
 
 
 
 
 | 22 | { | 
 
 
 
 
 | 23 | ConvertNode(root); | 
 
 
 
 
 | 24 | } | 
 
 
 
 
 | 25 |  | 
 
 
 
 
 | 26 | private void ConvertNode(Node node) | 
 
 
 
 
 | 27 | { | 
 
 
 
 
 | 28 | foreach (var instance in node.Instances) | 
 
 
 
 
 | 29 | ConvertInstance(instance); | 
 
 
 
 
 | 30 |  | 
 
 
 
 
 | 31 | foreach (var child in node.Nodes) | 
 
 
 
 
 | 32 | ConvertNode(child); | 
 
 
 
 
 | 33 | } | 
 
 
 
 
 | 34 |  | 
 
 
 
 
 | 35 | private void ConvertInstance(Instance instance) | 
 
 
 
 
 | 36 | { | 
 
 
 
 
 | 37 | var geometryInstance = instance as GeometryInstance; | 
 
 
 
 
 | 38 |  | 
 
 
 
 
 | 39 | if (geometryInstance != null) | 
 
 
 
 
 | 40 | { | 
 
 
 
 
 | 41 | ConvertGeometry(geometryInstance.Target); | 
 
 
 
 
 | 42 | return; | 
 
 
 
 
 | 43 | } | 
 
 
 
 
 | 44 | } | 
 
 
 
 
 | 45 |  | 
 
 
 
 
 | 46 | private void ConvertGeometry(Geometry geometry) | 
 
 
 
 
 | 47 | { | 
 
 
 
 
 | 48 | foreach (var primitives in geometry.Primitives) | 
 
 
 
 
 | 49 | { | 
 
 
 
 
 | 50 | if (primitives.PrimitiveType != MeshPrimitiveType.Polygons) | 
 
 
 
 
 | 51 | continue; | 
 
 
 
 
 | 52 |  | 
 
 
 
 
 | 53 | if (primitives.VertexCounts.All(c => c == 3)) | 
 
 
 
 
 | 54 | continue; | 
 
 
 
 
 | 55 |  | 
 
 
 
 
 | 56 | ConvertPolygons(geometry, primitives); | 
 
 
 
 
 | 57 | } | 
 
 
 
 
 | 58 | } | 
 
 
 
 
 | 59 |  | 
 
 
 
 
 | 60 | private void ConvertPolygons(Geometry geometry, MeshPrimitives primitives) | 
 
 
 
 
 | 61 | { | 
 
 
 
 
 | 62 | var positionInput = primitives.Inputs.FirstOrDefault(i => i.Semantic == Semantic.Position); | 
 
 
 
 
 | 63 |  | 
 
 
 
 
 | 64 | if (positionInput == null) | 
 
 
 
 
 | 65 | { | 
 
 
 
 
 | 66 | Console.Error.WriteLine("{0}: cannot find position input", geometry.Name); | 
 
 
 
 
 | 67 | return; | 
 
 
 
 
 | 68 | } | 
 
 
 
 
 | 69 |  | 
 
 
 
 
 | 70 | var newFaces = new List<int>(primitives.VertexCounts.Count * 2); | 
 
 
 
 
 | 71 | var newVertexCounts = new List<int>(primitives.VertexCounts.Count * 2); | 
 
 
 
 
 | 72 | int voffset = 0; | 
 
 
 
 
 | 73 |  | 
 
 
 
 
 | 74 | foreach (int vcount in primitives.VertexCounts) | 
 
 
 
 
 | 75 | { | 
 
 
 
 
 | 76 | if (vcount < 3) | 
 
 
 
 
 | 77 | { | 
 
 
 
 
 | 78 | Console.Error.WriteLine("{0}: skipping bad face (line)", geometry.Name); | 
 
 
 
 
 | 79 | } | 
 
 
 
 
 | 80 | else if (vcount <= maxEdges) | 
 
 
 
 
 | 81 | { | 
 
 
 
 
 | 82 | for (int i = 0; i < vcount; i++) | 
 
 
 
 
 | 83 | newFaces.Add(voffset + i); | 
 
 
 
 
 | 84 |  | 
 
 
 
 
 | 85 | newVertexCounts.Add(vcount); | 
 
 
 
 
 | 86 | } | 
 
 
 
 
 | 87 | else | 
 
 
 
 
 | 88 | { | 
 
 
 
 
 | 89 | ConvertPolygon(geometry, positionInput, voffset, vcount, newFaces, newVertexCounts); | 
 
 
 
 
 | 90 | } | 
 
 
 
 
 | 91 |  | 
 
 
 
 
 | 92 | voffset += vcount; | 
 
 
 
 
 | 93 | } | 
 
 
 
 
 | 94 |  | 
 
 
 
 
 | 95 | primitives.VertexCounts.Clear(); | 
 
 
 
 
 | 96 | primitives.VertexCounts.AddRange(newVertexCounts); | 
 
 
 
 
 | 97 |  | 
 
 
 
 
 | 98 | var oldIndices = new int[primitives.Inputs.Count][]; | 
 
 
 
 
 | 99 |  | 
 
 
 
 
 | 100 | for (int i = 0; i < primitives.Inputs.Count; i++) | 
 
 
 
 
 | 101 | { | 
 
 
 
 
 | 102 | var input = primitives.Inputs[i]; | 
 
 
 
 
 | 103 | oldIndices[i] = input.Indices.ToArray(); | 
 
 
 
 
 | 104 | input.Indices.Clear(); | 
 
 
 
 
 | 105 | } | 
 
 
 
 
 | 106 |  | 
 
 
 
 
 | 107 | for (int i = 0; i < primitives.Inputs.Count; i++) | 
 
 
 
 
 | 108 | { | 
 
 
 
 
 | 109 | var ni = primitives.Inputs[i].Indices; | 
 
 
 
 
 | 110 | var oi = oldIndices[i]; | 
 
 
 
 
 | 111 |  | 
 
 
 
 
 | 112 | foreach (int v in newFaces) | 
 
 
 
 
 | 113 | ni.Add(oi[v]); | 
 
 
 
 
 | 114 | } | 
 
 
 
 
 | 115 | } | 
 
 
 
 
 | 116 |  | 
 
 
 
 
 | 117 | private void ConvertPolygon(Geometry geometry, IndexedInput input, int offset, int vcount, List<int> newFaces, List<int> newVertexCounts) | 
 
 
 
 
 | 118 | { | 
 
 
 
 
 | 119 | var points = new Vector3[vcount]; | 
 
 
 
 
 | 120 |  | 
 
 
 
 
 | 121 | for (int i = 0; i < vcount; i++) | 
 
 
 
 
 | 122 | points[i] = Dae.Source.ReadVector3(input.Source, input.Indices[offset + i]); | 
 
 
 
 
 | 123 |  | 
 
 
 
 
 | 124 | int concave = -1; | 
 
 
 
 
 | 125 |  | 
 
 
 
 
 | 126 | for (int i = 0; i < vcount; i++) | 
 
 
 
 
 | 127 | { | 
 
 
 
 
 | 128 | Vector3 p0 = points[i]; | 
 
 
 
 
 | 129 | Vector3 p1 = points[(i + 1) % vcount]; | 
 
 
 
 
 | 130 |  | 
 
 
 
 
 | 131 | if (Vector3.Dot(p0, p1) < 0.0f) | 
 
 
 
 
 | 132 | { | 
 
 
 
 
 | 133 | concave = i; | 
 
 
 
 
 | 134 | break; | 
 
 
 
 
 | 135 | } | 
 
 
 
 
 | 136 | } | 
 
 
 
 
 | 137 |  | 
 
 
 
 
 | 138 | if (concave == -1) | 
 
 
 
 
 | 139 | { | 
 
 
 
 
 | 140 | for (int i = 0; i < vcount - 2; i++) | 
 
 
 
 
 | 141 | { | 
 
 
 
 
 | 142 | newFaces.Add(offset + 0); | 
 
 
 
 
 | 143 | newFaces.Add(offset + 1 + i); | 
 
 
 
 
 | 144 | newFaces.Add(offset + 2 + i); | 
 
 
 
 
 | 145 | newVertexCounts.Add(3); | 
 
 
 
 
 | 146 | } | 
 
 
 
 
 | 147 |  | 
 
 
 
 
 | 148 | return; | 
 
 
 
 
 | 149 | } | 
 
 
 
 
 | 150 |  | 
 
 
 
 
 | 151 | if (vcount == 4) | 
 
 
 
 
 | 152 | { | 
 
 
 
 
 | 153 | newFaces.Add(offset + concave); | 
 
 
 
 
 | 154 | newFaces.Add(offset + (concave + 1) % vcount); | 
 
 
 
 
 | 155 | newFaces.Add(offset + (concave + 2) % vcount); | 
 
 
 
 
 | 156 | newVertexCounts.Add(3); | 
 
 
 
 
 | 157 |  | 
 
 
 
 
 | 158 | newFaces.Add(offset + (concave + vcount - 1) % vcount); | 
 
 
 
 
 | 159 | newFaces.Add(offset + (concave + vcount - 2) % vcount); | 
 
 
 
 
 | 160 | newFaces.Add(offset + concave); | 
 
 
 
 
 | 161 | newVertexCounts.Add(3); | 
 
 
 
 
 | 162 |  | 
 
 
 
 
 | 163 | return; | 
 
 
 
 
 | 164 | } | 
 
 
 
 
 | 165 |  | 
 
 
 
 
 | 166 | Console.Error.WriteLine("{0}: skipping bad face (concave {1}-gon)", geometry.Name, vcount); | 
 
 
 
 
 | 167 | } | 
 
 
 
 
 | 168 | } | 
 
 
 
 
 | 169 | } |