source: OniSplit/Xml/XmlExporter.cs@ 1191

Last change on this file since 1191 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.3 KB
RevLine 
[1114]1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.IO;
5using System.Xml;
6using Oni.Collections;
7using Oni.Metadata;
8using Oni.Sound;
9
10namespace Oni.Xml
11{
12 internal sealed class XmlExporter : Exporter
13 {
14 private bool noAnimation;
15 private bool recursive;
16 private Totoro.Body animBody;
17 private bool mergeAnimations;
18 private Dae.Node animBodyNode;
19 private Totoro.Animation mergedAnim;
20 private string animDaeFileName;
21 private readonly Dictionary<InstanceDescriptor, string> externalChildren = new Dictionary<InstanceDescriptor, string>();
22 private readonly Set<InstanceDescriptor> queued = new Set<InstanceDescriptor>();
23 private readonly Queue<InstanceDescriptor> exportQueue = new Queue<InstanceDescriptor>();
24 private InstanceDescriptor mainDescriptor;
25 private string baseFileName;
26 private XmlWriter xml;
27
28 public XmlExporter(InstanceFileManager fileManager, string outputDirPath)
29 : base(fileManager, outputDirPath)
30 {
31 }
32
33 public bool NoAnimation
34 {
35 get { return noAnimation; }
36 set { noAnimation = value; }
37 }
38
39 public bool Recursive
40 {
41 get { return recursive; }
42 set { recursive = value; }
43 }
44
45 public Totoro.Body AnimationBody
46 {
47 get { return animBody; }
48 set
49 {
50 animBody = value;
51 animBodyNode = null;
52 }
53 }
54
55 public bool MergeAnimations
56 {
57 get { return mergeAnimations; }
58 set { mergeAnimations = value; }
59 }
60
61 protected override void ExportInstance(InstanceDescriptor descriptor)
62 {
63 exportQueue.Enqueue(descriptor);
64
65 mainDescriptor = descriptor;
66
67 string filePath = baseFileName = CreateFileName(descriptor, ".xml");
68 baseFileName = Path.GetFileNameWithoutExtension(filePath);
69
70 if (recursive && animBody == null && descriptor.Template.Tag == TemplateTag.ONCC)
71 animBody = Totoro.BodyDatReader.Read(descriptor);
72
73 using (xml = CreateXmlWriter(filePath))
74 ExportDescriptors(xml);
75 }
76
77 private void ExportChild(InstanceDescriptor descriptor)
78 {
79 if (descriptor.Template.Tag == TemplateTag.TRCM && mainDescriptor.Template.Tag == TemplateTag.TRBS)
80 {
81 xml.WriteValue(WriteBody(descriptor));
82 return;
83 }
84
85 if (descriptor.Template.Tag == TemplateTag.M3GM)
86 {
87 if (!descriptor.IsPlaceholder)
88 {
89 xml.WriteValue(WriteGeometry(descriptor));
90 return;
91 }
92
93 if (recursive)
94 {
95 var m3gmFile = InstanceFileManager.FindInstance(descriptor.FullName, descriptor.File);
96
97 if (m3gmFile != null && m3gmFile.Descriptors[0].Template.Tag == TemplateTag.M3GM && m3gmFile.Descriptors[0].Name == descriptor.Name)
98 {
99 xml.WriteValue(WriteGeometry(m3gmFile.Descriptors[0]));
100 return;
101 }
102 }
103 }
104
105 if (!recursive || !descriptor.HasName)
106 {
107 if (descriptor.HasName)
108 {
109 xml.WriteValue(descriptor.FullName);
110 }
111 else
112 {
113 xml.WriteValue(string.Format(CultureInfo.InvariantCulture, "#{0}", descriptor.Index));
114
115 if (queued.Add(descriptor))
116 exportQueue.Enqueue(descriptor);
117 }
118
119 return;
120 }
121
122 var childFile = InstanceFileManager.FindInstance(descriptor.FullName, descriptor.File);
123
124 if (childFile == null || childFile == mainDescriptor.File)
125 {
126 xml.WriteValue(descriptor.FullName);
127 return;
128 }
129
130 string fileName;
131
132 if (!externalChildren.TryGetValue(descriptor, out fileName))
133 {
134 var exporter = new XmlExporter(InstanceFileManager, OutputDirPath)
135 {
136 recursive = recursive,
137 animBody = animBody,
138 mergeAnimations = mergeAnimations
139 };
140
141 exporter.ExportFiles(new[] { childFile.FilePath });
142
143 fileName = Path.GetFileName(CreateFileName(descriptor, ".xml"));
144
145 externalChildren.Add(descriptor, fileName);
146 }
147
148 xml.WriteValue(fileName);
149 }
150
151 private static XmlWriter CreateXmlWriter(string filePath)
152 {
153 var settings = new XmlWriterSettings
154 {
155 CloseOutput = true,
156 Indent = true,
157 IndentChars = " "
158 };
159
160 var stream = File.Create(filePath);
161 var writer = XmlWriter.Create(stream, settings);
162
163 try
164 {
165 writer.WriteStartElement("Oni");
166 }
167 catch
168 {
169#if NETCORE
170 writer.Dispose();
171#else
172 writer.Close();
173#endif
174 throw;
175 }
176
177 return writer;
178 }
179
180 private void ExportDescriptors(XmlWriter writer)
181 {
182 while (exportQueue.Count > 0)
183 {
184 var descriptor = exportQueue.Dequeue();
185
186 if (descriptor.IsPlaceholder || (descriptor.HasName && descriptor != mainDescriptor))
187 continue;
188
189 switch (descriptor.Template.Tag)
190 {
191 case TemplateTag.TRAM:
192 WriteAnimation(descriptor);
193 break;
194
195 case TemplateTag.BINA:
196 WriteBinaryObject(descriptor);
197 break;
198
199 case TemplateTag.TXMP:
200 //
201 // Only export TXMP instances that have a name, the others
202 // are animation frames and they're exported as part of named textures
203 //
204
205 if (descriptor.HasName)
206 Oni.Motoko.TextureXmlExporter.Export(descriptor, writer, OutputDirPath, baseFileName);
207
208 break;
209
210 case TemplateTag.TXAN:
211 //
212 // Do nothing: TXAN instances are exported as part of TXMP instances
213 //
214 break;
215
216 case TemplateTag.OSBD:
217 WriteBinarySound(descriptor);
218 break;
219
220 default:
221 GenericXmlWriter.Write(xml, ExportChild, descriptor);
222 break;
223 }
224 }
225 }
226
227 private void WriteAnimation(InstanceDescriptor tram)
228 {
229 var anim = Totoro.AnimationDatReader.Read(tram);
230
231 if (animBody == null)
232 {
233 Totoro.AnimationXmlWriter.Write(anim, xml, null, 0, 0);
234 }
235 else
236 {
237 if (animBodyNode == null)
238 {
239 var textureWriter = new Motoko.TextureDaeWriter(OutputDirPath);
240 var geometryWriter = new Motoko.GeometryDaeWriter(textureWriter);
241 var bodyWriter = new Totoro.BodyDaeWriter(geometryWriter);
242
243 animBodyNode = bodyWriter.Write(animBody, false, null);
244 }
245
246 if (mergeAnimations)
247 {
248 if (mergedAnim == null)
249 {
250 mergedAnim = new Totoro.Animation();
251 animDaeFileName = tram.FullName + ".dae";
252 }
253
254 var startFrame = mergedAnim.Heights.Count;
255 Totoro.AnimationDaeWriter.AppendFrames(mergedAnim, anim);
256 var endFrame = mergedAnim.Heights.Count;
257
258 Totoro.AnimationXmlWriter.Write(anim, xml, animDaeFileName, startFrame, endFrame);
259 }
260 else
261 {
262 var fileName = tram.FullName + ".dae";
263
264 Totoro.AnimationDaeWriter.Write(animBodyNode, anim);
265
266 Dae.Writer.WriteFile(Path.Combine(OutputDirPath, fileName), new Dae.Scene
267 {
268 Nodes = { animBodyNode }
269 });
270
271 Totoro.AnimationXmlWriter.Write(anim, xml, fileName, 0, 0);
272 }
273 }
274 }
275
276 protected override void Flush()
277 {
278 if (mergedAnim != null)
279 {
280 Totoro.AnimationDaeWriter.Write(animBodyNode, mergedAnim);
281
282 Dae.Writer.WriteFile(Path.Combine(OutputDirPath, animDaeFileName), new Dae.Scene
283 {
284 Nodes = { animBodyNode }
285 });
286
287 mergedAnim = null;
288 }
289 }
290
291 private string WriteBody(InstanceDescriptor descriptor)
292 {
293 string fileName;
294
295 if (!externalChildren.TryGetValue(descriptor, out fileName))
296 {
297 var body = Totoro.BodyDatReader.Read(descriptor);
298
299 var textureWriter = new Motoko.TextureDaeWriter(OutputDirPath);
300 var geometryWriter = new Motoko.GeometryDaeWriter(textureWriter);
301 var bodyWriter = new Totoro.BodyDaeWriter(geometryWriter);
302
303 var pelvis = bodyWriter.Write(body, noAnimation, null);
304
305 fileName = string.Format("{0}_TRCM{1}.dae", mainDescriptor.FullName, descriptor.Index);
306
307 Dae.Writer.WriteFile(Path.Combine(OutputDirPath, fileName), new Dae.Scene
308 {
309 Nodes = { pelvis }
310 });
311
312 externalChildren.Add(descriptor, fileName);
313 }
314
315 return fileName;
316 }
317
318 private string WriteGeometry(InstanceDescriptor descriptor)
319 {
320 string fileName;
321
322 if (!externalChildren.TryGetValue(descriptor, out fileName))
323 {
324 var geometry = Motoko.GeometryDatReader.Read(descriptor);
325
326 var textureWriter = new Motoko.TextureDaeWriter(OutputDirPath);
327 var geometryWriter = new Motoko.GeometryDaeWriter(textureWriter);
328
329 if (descriptor.HasName)
330 fileName = descriptor.FullName + ".dae";
331 else
332 fileName = string.Format("{0}_{1}.dae", mainDescriptor.Name, descriptor.Index);
333
334 var node = geometryWriter.WriteNode(geometry, geometry.Name);
335
336 Dae.Writer.WriteFile(Path.Combine(OutputDirPath, fileName), new Dae.Scene
337 {
338 Nodes = { node }
339 });
340
341 externalChildren.Add(descriptor, fileName);
342 }
343
344 return fileName;
345 }
346
347 private void WriteBinarySound(InstanceDescriptor descriptor)
348 {
349 int dataSize, dataOffset;
350
351 using (var reader = descriptor.OpenRead())
352 {
353 dataSize = reader.ReadInt32();
354 dataOffset = reader.ReadInt32();
355 }
356
357 using (var rawReader = descriptor.GetRawReader(dataOffset))
358 {
359 OsbdXmlExporter.Export(rawReader, xml);
360 }
361 }
362
363 private void WriteBinaryObject(InstanceDescriptor descriptor)
364 {
365 int dataSize, dataOffset;
366
367 using (var reader = descriptor.OpenRead())
368 {
369 dataSize = reader.ReadInt32();
370 dataOffset = reader.ReadInt32();
371 }
372
373 using (var rawReader = descriptor.GetRawReader(dataOffset))
374 {
375 var tag = (BinaryTag)rawReader.ReadInt32();
376
377 switch (tag)
378 {
379 case BinaryTag.OBJC:
380 ObjcXmlExporter.Export(rawReader, xml);
381 break;
382
383 case BinaryTag.PAR3:
384 ParticleXmlExporter.Export(descriptor.FullName.Substring(8), rawReader, xml);
385 break;
386
387 case BinaryTag.TMBD:
388 TmbdXmlExporter.Export(rawReader, xml);
389 break;
390
391 case BinaryTag.ONIE:
392 OnieXmlExporter.Export(rawReader, xml);
393 break;
394
395 case BinaryTag.SABD:
396 SabdXmlExporter.Export(rawReader, xml);
397 break;
398
399 default:
400 throw new NotSupportedException(string.Format("Unsupported BINA type '{0}'", Utils.TagToString((int)tag)));
401 }
402 }
403 }
404 }
405}
Note: See TracBrowser for help on using the repository browser.