source: OniSplit/SceneExporter.cs@ 1143

Last change on this file since 1143 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: 13.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Xml;
5using Oni.Motoko;
6using Oni.Physics;
7using Oni.Totoro;
8
9namespace Oni
10{
11 internal class SceneExporter
12 {
13 private readonly InstanceFileManager fileManager;
14 private readonly string outputDirPath;
15 private readonly TextureDaeWriter textureWriter;
16 private readonly GeometryDaeWriter geometryWriter;
17 private readonly BodyDaeWriter bodyWriter;
18 private string basePath;
19
20 private class SceneNode
21 {
22 public string Name;
23 public readonly List<Geometry> Geometries = new List<Geometry>();
24 public readonly List<SceneNodeAnimation> Animations = new List<SceneNodeAnimation>();
25 public readonly List<SceneNode> Nodes = new List<SceneNode>();
26 public Body Body;
27 public bool IsCamera;
28 }
29
30 private class SceneNodeAnimation
31 {
32 public int Start;
33 public ObjectAnimation ObjectAnimation;
34 }
35
36 public SceneExporter(InstanceFileManager fileManager, string outputDirPath)
37 {
38 this.fileManager = fileManager;
39 this.outputDirPath = outputDirPath;
40
41 textureWriter = new TextureDaeWriter(outputDirPath);
42 geometryWriter = new GeometryDaeWriter(textureWriter);
43 bodyWriter = new BodyDaeWriter(geometryWriter);
44 }
45
46 public void ExportScene(string sourceFilePath)
47 {
48 basePath = Path.GetDirectoryName(sourceFilePath);
49
50 var scene = new Dae.Scene();
51
52 var settings = new XmlReaderSettings
53 {
54 IgnoreWhitespace = true,
55 IgnoreProcessingInstructions = true,
56 IgnoreComments = true
57 };
58
59 var nodes = new List<SceneNode>();
60
61 using (var xml = XmlReader.Create(sourceFilePath, settings))
62 {
63 scene.Name = xml.GetAttribute("Name");
64 xml.ReadStartElement("Scene");
65
66 while (xml.IsStartElement())
67 nodes.Add(ReadNode(xml));
68
69 xml.ReadEndElement();
70 }
71
72 foreach (var node in nodes)
73 {
74 scene.Nodes.Add(WriteNode(node, null));
75 }
76
77 Dae.Writer.WriteFile(Path.Combine(outputDirPath, Path.GetFileNameWithoutExtension(sourceFilePath)) + ".dae", scene);
78 }
79
80 private string ResolvePath(string path)
81 {
82 return Path.Combine(basePath, path);
83 }
84
85
86 private SceneNode ReadNode(XmlReader xml)
87 {
88 var node = new SceneNode
89 {
90 Name = xml.GetAttribute("Name")
91 };
92
93 xml.ReadStartElement("Node");
94
95 while (xml.IsStartElement())
96 {
97 switch (xml.LocalName)
98 {
99 case "Geometry":
100 ReadGeometry(xml, node);
101 break;
102 case "Body":
103 ReadBody(xml, node);
104 break;
105 case "Camera":
106 ReadCamera(xml, node);
107 break;
108 case "Animation":
109 ReadAnimation(xml, node);
110 break;
111 case "Node":
112 node.Nodes.Add(ReadNode(xml));
113 break;
114 default:
115 Console.WriteLine("Unknown element name {0}", xml.LocalName);
116 xml.Skip();
117 break;
118 }
119 }
120
121 xml.ReadEndElement();
122
123 return node;
124 }
125
126 private void ReadGeometry(XmlReader xml, SceneNode node)
127 {
128 var file = fileManager.OpenFile(ResolvePath(xml.ReadElementContentAsString()));
129 var geometry = GeometryDatReader.Read(file.Descriptors[0]);
130
131 node.Geometries.Add(geometry);
132 }
133
134 private void ReadBody(XmlReader xml, SceneNode node)
135 {
136 var file = fileManager.OpenFile(ResolvePath(xml.ReadElementContentAsString()));
137 var body = BodyDatReader.Read(file.Descriptors[0]);
138
139 node.Body = body;
140
141 ReadBodyNode(node, body.Root);
142 }
143
144 private static void ReadBodyNode(SceneNode node, BodyNode bodyNode)
145 {
146 node.Name = bodyNode.Name;
147 node.Geometries.Add(bodyNode.Geometry);
148
149 foreach (var childBodyNode in bodyNode.Nodes)
150 {
151 var childNode = new SceneNode();
152 node.Nodes.Add(childNode);
153 ReadBodyNode(childNode, childBodyNode);
154 }
155 }
156
157 private void ReadAnimation(XmlReader xml, SceneNode node)
158 {
159 var startValue = xml.GetAttribute("Start");
160 var isMax = xml.GetAttribute("Type") == "Max";
161 var noRotation = xml.GetAttribute("NoRotation") == "true";
162 var filePath = xml.ReadElementContentAsString();
163
164 var start = string.IsNullOrEmpty(startValue) ? 0 : int.Parse(startValue);
165 var file = fileManager.OpenFile(ResolvePath(filePath));
166
167 if (node.Body != null)
168 {
169 var animations = AnimationDatReader.Read(file.Descriptors[0]).ToObjectAnimation(node.Body);
170
171 ReadBodyAnimation(start, node, node.Body.Root, animations);
172 }
173 else
174 {
175 node.Animations.Add(new SceneNodeAnimation
176 {
177 Start = start,
178 ObjectAnimation = ObjectDatReader.ReadAnimation(file.Descriptors[0])
179 });
180
181 if (noRotation)
182 {
183 foreach (var key in node.Animations.Last().ObjectAnimation.Keys)
184 key.Rotation = Quaternion.Identity;
185 }
186 else if (isMax)
187 {
188 foreach (var key in node.Animations.Last().ObjectAnimation.Keys)
189 key.Rotation *= Quaternion.CreateFromAxisAngle(Vector3.UnitX, MathHelper.HalfPi);
190 }
191 }
192 }
193
194 private void ReadBodyAnimation(int start, SceneNode node, BodyNode bodyNode, ObjectAnimation[] animations)
195 {
196 node.Animations.Add(new SceneNodeAnimation
197 {
198 Start = start,
199 ObjectAnimation = animations[bodyNode.Index]
200 });
201
202 for (int i = 0; i < node.Nodes.Count; i++)
203 ReadBodyAnimation(start, node.Nodes[i], bodyNode.Nodes[i], animations);
204 }
205
206 private void ReadCamera(XmlReader xml, SceneNode node)
207 {
208 node.IsCamera = true;
209
210 xml.Skip();
211 }
212
213
214 private Dae.Node WriteNode(SceneNode node, List<ObjectAnimationKey> parentFrames)
215 {
216 var daeNode = new Dae.Node
217 {
218 Name = node.Name
219 };
220
221 foreach (var geometry in node.Geometries)
222 daeNode.Instances.Add(geometryWriter.WriteGeometryInstance(geometry, geometry.Name));
223
224 if (node.IsCamera)
225 WriteCamera(daeNode);
226
227 List<ObjectAnimationKey> frames = null;
228
229 if (node.Animations.Count > 0)
230 {
231 frames = BuildFrames(node);
232 WriteAnimation(daeNode, BuildLocalFrames(node.Body == null ? parentFrames : null, frames));
233 }
234
235 foreach (var child in node.Nodes)
236 daeNode.Nodes.Add(WriteNode(child, frames));
237
238 return daeNode;
239 }
240
241 private static List<ObjectAnimationKey> BuildFrames(SceneNode node)
242 {
243 var frames = new List<ObjectAnimationKey>();
244
245 foreach (var animation in node.Animations)
246 {
247 var animFrames = animation.ObjectAnimation.Interpolate();
248 var start = animation.Start;
249
250 if (frames.Count > 0)
251 start += frames.Last().Time + 1;
252
253 foreach (var frame in animFrames)
254 frame.Time += start;
255
256 if (frames.Count > 0)
257 {
258 while (frames.Last().Time >= animFrames.First().Time)
259 {
260 frames.RemoveAt(frames.Count - 1);
261 }
262
263 while (frames.Last().Time + 1 < animFrames.First().Time)
264 {
265 frames.Add(new ObjectAnimationKey
266 {
267 Time = frames.Last().Time + 1,
268 Rotation = frames.Last().Rotation,
269 Translation = frames.Last().Translation,
270 Scale = frames.Last().Scale
271 });
272 }
273 }
274
275 frames.AddRange(animFrames);
276 }
277
278 return frames;
279 }
280
281 private static List<ObjectAnimationKey> BuildLocalFrames(List<ObjectAnimationKey> parentFrames, List<ObjectAnimationKey> frames)
282 {
283 var localFrames = frames;
284
285 if (parentFrames != null)
286 {
287 localFrames = new List<ObjectAnimationKey>(localFrames.Count);
288
289 for (int i = 0; i < frames.Count; i++)
290 {
291 var frame = frames[i];
292 var parentFrame = parentFrames[i];
293
294 localFrames.Add(new ObjectAnimationKey
295 {
296 Time = frame.Time,
297 Scale = frame.Scale / parentFrame.Scale,
298 Rotation = Quaternion.Conjugate(parentFrame.Rotation) * frame.Rotation,
299 Translation = Vector3.Transform(frame.Translation - parentFrame.Translation, parentFrame.Rotation.Inverse()) / parentFrame.Scale
300 });
301 }
302 }
303
304 return localFrames;
305 }
306
307 private static void WriteAnimation(Dae.Node node, List<ObjectAnimationKey> frames)
308 {
309 var times = new float[frames.Count];
310 var interpolations = new string[times.Length];
311 var positions = new Vector3[frames.Count];
312 var angles = new Vector3[frames.Count];
313
314 for (int i = 0; i < times.Length; ++i)
315 times[i] = frames[i].Time / 60.0f;
316
317 for (int i = 0; i < interpolations.Length; i++)
318 interpolations[i] = "LINEAR";
319
320 for (int i = 0; i < frames.Count; i++)
321 positions[i] = frames[i].Translation;
322
323 for (int i = 0; i < frames.Count; i++)
324 angles[i] = frames[i].Rotation.ToEulerXYZ();
325
326 var translate = node.Transforms.Translate("translate", positions[0]); ;
327 var rotateX = node.Transforms.Rotate("rotX", Vector3.UnitX, angles[0].X);
328 var rotateY = node.Transforms.Rotate("rotY", Vector3.UnitY, angles[0].Y);
329 var rotateZ = node.Transforms.Rotate("rotZ", Vector3.UnitZ, angles[0].Z);
330 var scale = node.Transforms.Scale("scale", frames[0].Scale);
331
332 WriteSampler(times, interpolations, i => positions[i].X, translate, "X");
333 WriteSampler(times, interpolations, i => positions[i].Y, translate, "Y");
334 WriteSampler(times, interpolations, i => positions[i].Z, translate, "Z");
335 WriteSampler(times, interpolations, i => angles[i].X, rotateX, "ANGLE");
336 WriteSampler(times, interpolations, i => angles[i].Y, rotateY, "ANGLE");
337 WriteSampler(times, interpolations, i => angles[i].Z, rotateZ, "ANGLE");
338 }
339
340 private static void WriteSampler(float[] times, string[] interpolations, Func<int, float> getValue, Dae.Transform transform, string targetName)
341 {
342 var values = new float[times.Length];
343
344 for (int i = 0; i < values.Length; ++i)
345 values[i] = getValue(i);
346
347 transform.BindAnimation(targetName, new Dae.Sampler
348 {
349 Inputs = {
350 new Dae.Input(Dae.Semantic.Input, new Dae.Source(times, 1)),
351 new Dae.Input(Dae.Semantic.Output, new Dae.Source(values, 1)),
352 new Dae.Input(Dae.Semantic.Interpolation, new Dae.Source(interpolations, 1))
353 }
354 });
355 }
356
357 private static void WriteCamera(Dae.Node daeNode)
358 {
359 daeNode.Instances.Add(new Dae.CameraInstance
360 {
361 Target = new Dae.Camera
362 {
363 XFov = 45.0f,
364 AspectRatio = 4.0f / 3.0f,
365 ZNear = 1.0f,
366 ZFar = 10000.0f
367 }
368 });
369 }
370 }
371}
Note: See TracBrowser for help on using the repository browser.