source: OniSplit/Akira/RoomDaeReader.cs@ 1170

Last change on this file since 1170 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: 7.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using Oni.Imaging;
5
6namespace Oni.Akira
7{
8 internal class RoomDaeReader
9 {
10 private readonly PolygonMesh mesh;
11 private readonly List<Vector3> positions;
12 private readonly Stack<Matrix> nodeTransformStack;
13 private Dae.Scene scene;
14 private Matrix nodeTransform;
15
16 public static PolygonMesh Read(Dae.Scene scene)
17 {
18 var reader = new RoomDaeReader();
19 reader.ReadScene(scene);
20 return reader.mesh;
21 }
22
23 private RoomDaeReader()
24 {
25 mesh = new PolygonMesh(new MaterialLibrary());
26
27 positions = mesh.Points;
28
29 nodeTransformStack = new Stack<Matrix>();
30 nodeTransform = Matrix.Identity;
31 }
32
33 private void ReadScene(Dae.Scene scene)
34 {
35 this.scene = scene;
36
37 foreach (Dae.Node node in scene.Nodes)
38 ReadNode(node);
39 }
40
41 private void ReadNode(Dae.Node node)
42 {
43 nodeTransformStack.Push(nodeTransform);
44
45 foreach (var transform in node.Transforms)
46 nodeTransform = transform.ToMatrix() * nodeTransform;
47
48 foreach (var geometryInstance in node.GeometryInstances)
49 ReadGeometryInstance(node, geometryInstance);
50
51 foreach (var child in node.Nodes)
52 ReadNode(child);
53
54 nodeTransform = nodeTransformStack.Pop();
55 }
56
57 private void ReadGeometryInstance(Dae.Node node, Dae.GeometryInstance instance)
58 {
59 var geometry = instance.Target;
60
61 foreach (var primitives in geometry.Primitives)
62 {
63 if (primitives.PrimitiveType != Dae.MeshPrimitiveType.Polygons)
64 {
65 Console.Error.WriteLine("Unsupported primitive type '{0}' found in geometry '{1}', ignoring.", primitives.PrimitiveType, geometry.Id);
66 continue;
67 }
68
69 ReadPolygonPrimitives(node, primitives, instance.Materials.Find(m => m.Symbol == primitives.MaterialSymbol));
70 }
71 }
72
73 private void ReadPolygonPrimitives(Dae.Node node, Dae.MeshPrimitives primitives, Dae.MaterialInstance materialInstance)
74 {
75 var positionInput = primitives.Inputs.FirstOrDefault(i => i.Semantic == Dae.Semantic.Position);
76 var positionIndices = ReadInputIndexed(positionInput, positions, Dae.Source.ReadVector3);
77
78 foreach (int i in positionIndices)
79 positions[i] = Vector3.Transform(positions[i], ref nodeTransform);
80
81 int startIndex = 0;
82
83 foreach (int vertexCount in primitives.VertexCounts)
84 {
85 var polygon = CreatePolygon(positionIndices, startIndex, vertexCount);
86 startIndex += vertexCount;
87
88 if (polygon == null)
89 {
90 Console.Error.WriteLine("BNV polygon: discarded, polygon is degenerate");
91 continue;
92 }
93
94 polygon.FileName = node.FileName;
95 polygon.ObjectName = node.Name;
96
97 if (Math.Abs(polygon.Plane.Normal.Y) < 0.0001f)
98 {
99 if (polygon.BoundingBox.Height < 1.0f)
100 {
101 Console.Error.WriteLine("BNV polygon: discarded, ghost height must be greater than 1, it is {0}", polygon.BoundingBox.Height);
102 continue;
103 }
104
105 if (polygon.PointIndices.Length != 4)
106 {
107 Console.Error.WriteLine("BNV polygon: discarded, ghost is a {0}-gon", polygon.PointIndices.Length);
108 continue;
109 }
110
111 mesh.Ghosts.Add(polygon);
112 }
113 else if ((polygon.Flags & GunkFlags.Horizontal) != 0)
114 {
115 mesh.Floors.Add(polygon);
116 }
117 else
118 {
119 Console.Error.WriteLine("BNV polygon: discarded, not a ghost and not a floor");
120 }
121 }
122 }
123
124 private Polygon CreatePolygon(int[] positionIndices, int startIndex, int vertexCount)
125 {
126 int endIndex = startIndex + vertexCount;
127
128 var indices = new List<int>(vertexCount);
129
130 for (int i = startIndex; i < endIndex; i++)
131 {
132 int i0 = positionIndices[i == startIndex ? endIndex - 1 : i - 1];
133 int i1 = positionIndices[i];
134 int i2 = positionIndices[i + 1 == endIndex ? startIndex : i + 1];
135
136 if (i0 == i1)
137 {
138 Console.Error.WriteLine("BNV polygon: discarding degenerate edge {0}", mesh.Points[i1]);
139 continue;
140 }
141
142 Vector3 p0 = mesh.Points[i0];
143 Vector3 p1 = mesh.Points[i1];
144 Vector3 p2 = mesh.Points[i2];
145
146 Vector3 p1p0 = p1 - p0;
147 Vector3 p2p1 = p2 - p1;
148
149 //if (p1p0.LengthSquared() < 0.000001f)
150 //{
151 // Console.Error.WriteLine("BNV polygon: merging duplicate points {0} {1}", p0, p1);
152 // continue;
153 //}
154
155 if (Vector3.Cross(p2p1, p1p0).LengthSquared() < 0.000001f)
156 {
157 //Console.Error.WriteLine("BNV polygon: combining colinear edges at {0}", p1);
158 continue;
159 }
160
161 indices.Add(i1);
162 }
163
164 var indicesArray = indices.ToArray();
165
166 if (CheckDegenerate(mesh.Points, indicesArray))
167 return null;
168
169 return new Polygon(mesh, indicesArray);
170 }
171
172 private static bool CheckDegenerate(List<Vector3> positions, int[] indices)
173 {
174 if (indices.Length < 3)
175 return true;
176
177 Vector3 p0 = positions[indices[0]];
178 Vector3 p1 = positions[indices[1]];
179 Vector3 s0, s1, c;
180
181 for (int i = 2; i < indices.Length; i++)
182 {
183 Vector3 p2 = positions[indices[i]];
184
185 Vector3.Substract(ref p0, ref p1, out s0);
186 Vector3.Substract(ref p2, ref p1, out s1);
187 Vector3.Cross(ref s0, ref s1, out c);
188
189 if (Math.Abs(c.LengthSquared()) < 0.0001f && Vector3.Dot(ref s0, ref s1) > 0.0f)
190 return true;
191
192 p0 = p1;
193 p1 = p2;
194 }
195
196 return false;
197 }
198
199 private static int[] ReadInputIndexed<T>(Dae.IndexedInput input, List<T> list, Func<Dae.Source, int, T> elementReader)
200 where T : struct
201 {
202 var indices = new int[input.Indices.Count];
203
204 for (int i = 0; i < input.Indices.Count; i++)
205 {
206 var v = elementReader(input.Source, input.Indices[i]);
207 indices[i] = list.Count;
208 list.Add(v);
209 }
210
211 return indices;
212 }
213 }
214}
Note: See TracBrowser for help on using the repository browser.