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