[1114] | 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 | }
|
---|