source: OniSplit/Akira/RoomDaeWriter.cs

Last change on this file 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: 12.4 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.IO;
5using Oni.Collections;
6using Oni.Imaging;
7
8namespace Oni.Akira
9{
10 internal class RoomDaeWriter
11 {
12 #region Private data
13 private readonly PolygonMesh source;
14 private DaeSceneBuilder world;
15
16 private static readonly string[] objectTypeNames = new[] {
17 "",
18 "char",
19 "patr",
20 "door",
21 "flag",
22 "furn",
23 "",
24 "",
25 "part",
26 "pwru",
27 "sndg",
28 "trgv",
29 "weap",
30 "trig",
31 "turr",
32 "cons",
33 "cmbt",
34 "mele",
35 "neut"
36 };
37
38 #endregion
39
40 #region private class DaePolygon
41
42 private class DaePolygon
43 {
44 private readonly Polygon source;
45 private readonly Material material;
46 private readonly int[] pointIndices;
47 private readonly int[] texCoordIndices;
48 private readonly int[] colorIndices;
49
50 public DaePolygon(Polygon source, int[] pointIndices, int[] texCoordIndices, int[] colorIndices)
51 {
52 this.source = source;
53 this.material = source.Material;
54 this.pointIndices = pointIndices;
55 this.texCoordIndices = texCoordIndices;
56 this.colorIndices = colorIndices;
57 }
58
59 public DaePolygon(Material material, int[] pointIndices, int[] texCoordIndices)
60 {
61 this.material = material;
62 this.pointIndices = pointIndices;
63 this.texCoordIndices = texCoordIndices;
64 }
65
66 public Polygon Source => source;
67 public Material Material => material;
68
69 public int[] PointIndices => pointIndices;
70 public int[] TexCoordIndices => texCoordIndices;
71 public int[] ColorIndices => colorIndices;
72 }
73
74 #endregion
75 #region private class DaeMeshBuilder
76
77 private class DaeMeshBuilder
78 {
79 private readonly List<DaePolygon> polygons = new List<DaePolygon>();
80 private readonly List<Vector3> points = new List<Vector3>();
81 private readonly Dictionary<Vector3, int> uniquePoints = new Dictionary<Vector3, int>();
82 private readonly List<Vector2> texCoords = new List<Vector2>();
83 private readonly Dictionary<Vector2, int> uniqueTexCoords = new Dictionary<Vector2, int>();
84 private readonly List<Color> colors = new List<Color>();
85 private readonly Dictionary<Color, int> uniqueColors = new Dictionary<Color, int>();
86 private string name;
87 private Vector3 translation;
88 private Dae.Geometry geometry;
89
90 public DaeMeshBuilder(string name)
91 {
92 this.name = name;
93 }
94
95 public string Name
96 {
97 get { return name; }
98 set { name = value; }
99 }
100
101 public Vector3 Translation => translation;
102
103 public void ResetTransform()
104 {
105 //
106 // Attempt to un-bake the translation of the furniture
107 //
108
109 Vector3 center = BoundingSphere.CreateFromPoints(points).Center;
110
111 BoundingBox bbox = BoundingBox.CreateFromPoints(points);
112 center.Y = bbox.Min.Y;
113
114 translation = center;
115
116 for (int i = 0; i < points.Count; i++)
117 points[i] -= center;
118 }
119
120 public void AddPolygon(Polygon polygon)
121 {
122 polygons.Add(new DaePolygon(
123 polygon,
124 Remap(polygon.Mesh.Points, polygon.PointIndices, points, uniquePoints),
125 null,
126 null));
127 }
128
129 public IEnumerable<Polygon> Polygons => from p in polygons
130 where p.Source != null
131 select p.Source;
132
133 private static int[] Remap<T>(IList<T> values, int[] indices, List<T> list, Dictionary<T, int> unique) where T : struct
134 {
135 var result = new int[indices.Length];
136
137 for (int i = 0; i < indices.Length; i++)
138 result[i] = AddUnique(list, unique, values[indices[i]]);
139
140 return result;
141 }
142
143 private static int[] Remap<T>(IList<T> values, List<T> list, Dictionary<T, int> unique) where T : struct
144 {
145 var result = new int[values.Count];
146
147 for (int i = 0; i < values.Count; i++)
148 result[i] = AddUnique(list, unique, values[i]);
149
150 return result;
151 }
152
153 private static int AddUnique<T>(List<T> list, Dictionary<T, int> unique, T value) where T : struct
154 {
155 int index;
156
157 if (!unique.TryGetValue(value, out index))
158 {
159 index = list.Count;
160 unique.Add(value, index);
161 list.Add(value);
162 }
163
164 return index;
165 }
166
167 public void Build()
168 {
169 var positionSource = new Dae.Source(points);
170 var primitives = new Dae.MeshPrimitives(Dae.MeshPrimitiveType.Polygons);
171 var posInput = new Dae.IndexedInput(Dae.Semantic.Position, positionSource);
172
173 primitives.Inputs.Add(posInput);
174
175 foreach (var poly in polygons)
176 {
177 primitives.VertexCounts.Add(poly.PointIndices.Length);
178
179 posInput.Indices.AddRange(poly.PointIndices);
180 }
181
182 geometry = new Dae.Geometry
183 {
184 Name = Name + "_geo",
185 Vertices = { new Dae.Input(Dae.Semantic.Position, positionSource) },
186 Primitives = { primitives }
187 };
188 }
189
190 public Dae.Geometry Geometry
191 {
192 get
193 {
194 return geometry;
195 }
196 }
197 }
198
199 #endregion
200 #region private class DaeSceneBuilder
201
202 private class DaeSceneBuilder
203 {
204 private readonly Dae.Scene scene;
205 private readonly Dictionary<string, DaeMeshBuilder> nameMeshBuilder;
206 private readonly List<DaeMeshBuilder> meshBuilders;
207 private readonly Dictionary<Material, Dae.Material> materials;
208 private string imagesFolder = "images";
209
210 public DaeSceneBuilder()
211 {
212 scene = new Dae.Scene();
213 nameMeshBuilder = new Dictionary<string, DaeMeshBuilder>(StringComparer.Ordinal);
214 meshBuilders = new List<DaeMeshBuilder>();
215 materials = new Dictionary<Material, Dae.Material>();
216 }
217
218 public string ImagesFolder
219 {
220 get { return imagesFolder; }
221 set { imagesFolder = value; }
222 }
223
224 public DaeMeshBuilder GetMeshBuilder(string name)
225 {
226 DaeMeshBuilder result;
227
228 if (!nameMeshBuilder.TryGetValue(name, out result))
229 {
230 result = new DaeMeshBuilder(name);
231 nameMeshBuilder.Add(name, result);
232 meshBuilders.Add(result);
233 }
234
235 return result;
236 }
237
238 public IEnumerable<DaeMeshBuilder> MeshBuilders
239 {
240 get { return meshBuilders; }
241 }
242
243 public Dae.Material GetMaterial(Material material)
244 {
245 Dae.Material result;
246
247 if (!materials.TryGetValue(material, out result))
248 {
249 result = new Dae.Material();
250 materials.Add(material, result);
251 }
252
253 return result;
254 }
255
256 public void Build()
257 {
258 BuildNodes();
259 BuildMaterials();
260 }
261
262 private void BuildNodes()
263 {
264 foreach (var meshBuilder in meshBuilders)
265 {
266 meshBuilder.Build();
267
268 var inst = new Dae.GeometryInstance(meshBuilder.Geometry);
269
270 var node = new Dae.Node();
271 node.Name = meshBuilder.Name;
272 node.Instances.Add(inst);
273
274 if (meshBuilder.Translation != Vector3.Zero)
275 node.Transforms.Add(new Dae.TransformTranslate(meshBuilder.Translation));
276
277 scene.Nodes.Add(node);
278 }
279 }
280
281 private void BuildMaterials()
282 {
283 foreach (KeyValuePair<Material, Dae.Material> pair in materials)
284 {
285 var material = pair.Key;
286
287 var image = new Dae.Image
288 {
289 FilePath = "./" + GetImageFileName(material).Replace('\\', '/'),
290 Name = material.Name + "_img"
291 };
292
293 var effectSurface = new Dae.EffectSurface(image);
294
295 var effectSampler = new Dae.EffectSampler(effectSurface)
296 {
297 //WrapS = texture.WrapU ? Dae.EffectSamplerWrap.Wrap : Dae.EffectSamplerWrap.None,
298 //WrapT = texture.WrapV ? Dae.EffectSamplerWrap.Wrap : Dae.EffectSamplerWrap.None
299 };
300
301 var effectTexture = new Dae.EffectTexture(effectSampler, "diffuse_TEXCOORD");
302
303 var effect = new Dae.Effect
304 {
305 Name = material.Name + "_fx",
306 AmbientValue = Vector4.One,
307 SpecularValue = Vector4.Zero,
308 DiffuseValue = effectTexture,
309 TransparentValue = material.Image.HasAlpha ? effectTexture : null,
310 Parameters = {
311 new Dae.EffectParameter("surface", effectSurface),
312 new Dae.EffectParameter("sampler", effectSampler)
313 }
314 };
315
316 var daeMaterial = pair.Value;
317 daeMaterial.Name = material.Name;
318 daeMaterial.Effect = effect;
319 }
320 }
321
322 private string GetImageFileName(Material material)
323 {
324 if (material.IsMarker)
325 return Path.Combine("markers", material.Name + ".tga");
326
327 return Path.Combine(imagesFolder, material.Name + ".tga");
328 }
329
330 public void Write(string filePath)
331 {
332 string outputDirPath = Path.GetDirectoryName(filePath);
333
334 foreach (var material in materials.Keys)
335 TgaWriter.Write(material.Image, Path.Combine(outputDirPath, GetImageFileName(material)));
336
337 Dae.Writer.WriteFile(filePath, scene);
338 }
339 }
340
341 #endregion
342
343 public static void Write(PolygonMesh mesh, string filePath)
344 {
345 var writer = new RoomDaeWriter(mesh);
346 writer.WriteGeometry();
347 writer.world.Write(filePath);
348 }
349
350 private RoomDaeWriter(PolygonMesh source)
351 {
352 this.source = source;
353 }
354
355 private void WriteGeometry()
356 {
357 world = new DaeSceneBuilder();
358
359 for (int i = 0; i < source.Polygons.Count; i++)
360 {
361 var polygon = source.Polygons[i];
362
363 var name = string.Format(CultureInfo.InvariantCulture, "floor_{0}", i);
364 var meshBuilder = world.GetMeshBuilder(name);
365 meshBuilder.AddPolygon(polygon);
366 }
367
368 foreach (var meshBuilder in world.MeshBuilders)
369 {
370 meshBuilder.ResetTransform();
371 }
372
373 world.Build();
374 }
375 }
376}
Note: See TracBrowser for help on using the repository browser.