source: OniSplit/Dae/Converters/FaceConverter.cs@ 1162

Last change on this file since 1162 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 5.1 KB
RevLine 
[1114]1using System;
2using System.Collections.Generic;
3using Oni.Collections;
4
5namespace 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}
Note: See TracBrowser for help on using the repository browser.