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 |
} |