source: OniSplit/Totoro/AnimationXmlReader.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: 16.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Xml;
5using Oni.Metadata;
6using Oni.Xml;
7
8namespace Oni.Totoro
9{
10 internal class AnimationXmlReader
11 {
12 private const string ns = "";
13 private static readonly char[] emptyChars = new char[0];
14 private XmlReader xml;
15 private string basePath;
16 private Animation animation;
17 private AnimationDaeReader daeReader;
18
19 private AnimationXmlReader()
20 {
21 }
22
23 public static Animation Read(XmlReader xml, string baseDir)
24 {
25 var reader = new AnimationXmlReader
26 {
27 xml = xml,
28 basePath = baseDir,
29 animation = new Animation()
30 };
31
32 var animation = reader.Read();
33 animation.ValidateFrames();
34 return animation;
35 }
36
37 private Animation Read()
38 {
39 animation.Name = xml.GetAttribute("Name");
40 xml.ReadStartElement("Animation", ns);
41
42 if (xml.IsStartElement("DaeImport") || xml.IsStartElement("Import"))
43 ImportDaeAnimation();
44
45 xml.ReadStartElement("Lookup");
46 animation.Type = MetaEnum.Parse<AnimationType>(xml.ReadElementContentAsString("Type", ns));
47 animation.AimingType = MetaEnum.Parse<AnimationType>(xml.ReadElementContentAsString("AimingType", ns));
48 animation.FromState = MetaEnum.Parse<AnimationState>(xml.ReadElementContentAsString("FromState", ns));
49 animation.ToState = MetaEnum.Parse<AnimationState>(xml.ReadElementContentAsString("ToState", ns));
50 animation.Varient = MetaEnum.Parse<AnimationVarient>(xml.ReadElementContentAsString("Varient", ns));
51 animation.FirstLevelAvailable = xml.ReadElementContentAsInt("FirstLevel", ns);
52 ReadRawArray("Shortcuts", animation.Shortcuts, Read);
53 xml.ReadEndElement();
54
55 animation.Flags = MetaEnum.Parse<AnimationFlags>(xml.ReadElementContentAsString("Flags", ns));
56 xml.ReadStartElement("Atomic", ns);
57 animation.AtomicStart = xml.ReadElementContentAsInt("Start", ns);
58 animation.AtomicEnd = xml.ReadElementContentAsInt("End", ns);
59 xml.ReadEndElement();
60 xml.ReadStartElement("Invulnerable", ns);
61 animation.InvulnerableStart = xml.ReadElementContentAsInt("Start", ns);
62 animation.InvulnerableEnd = xml.ReadElementContentAsInt("End", ns);
63 xml.ReadEndElement();
64 xml.ReadStartElement("Overlay", ns);
65 animation.OverlayUsedBones = MetaEnum.Parse<BoneMask>(xml.ReadElementContentAsString("UsedBones", ns));
66 animation.OverlayReplacedBones = MetaEnum.Parse<BoneMask>(xml.ReadElementContentAsString("ReplacedBones", ns));
67 xml.ReadEndElement();
68
69 xml.ReadStartElement("DirectAnimations", ns);
70 animation.DirectAnimations[0] = xml.ReadElementContentAsString("Link", ns);
71 animation.DirectAnimations[1] = xml.ReadElementContentAsString("Link", ns);
72 xml.ReadEndElement();
73 xml.ReadStartElement("Pause");
74 animation.HardPause = xml.ReadElementContentAsInt("Hard", ns);
75 animation.SoftPause = xml.ReadElementContentAsInt("Soft", ns);
76 xml.ReadEndElement();
77 xml.ReadStartElement("Interpolation", ns);
78 animation.InterpolationEnd = xml.ReadElementContentAsInt("End", ns);
79 animation.InterpolationMax = xml.ReadElementContentAsInt("Max", ns);
80 xml.ReadEndElement();
81
82 animation.FinalRotation = MathHelper.ToRadians(xml.ReadElementContentAsFloat("FinalRotation", ns));
83 animation.Direction = MetaEnum.Parse<Direction>(xml.ReadElementContentAsString("Direction", ns));
84 animation.Vocalization = xml.ReadElementContentAsInt("Vocalization", ns);
85 animation.ActionFrame = xml.ReadElementContentAsInt("ActionFrame", ns);
86 animation.Impact = xml.ReadElementContentAsString("Impact", ns);
87
88 ReadRawArray("Particle", animation.Particles, Read);
89 ReadRawArray("MotionBlur", animation.MotionBlur, Read);
90 ReadRawArray("Footsteps", animation.Footsteps, Read);
91 ReadRawArray("Sounds", animation.Sounds, Read);
92
93 if (daeReader == null)
94 {
95 ReadHeights();
96 ReadVelocities();
97 ReadRotations();
98 ReadPositions();
99 }
100
101 ReadThrowInfo();
102 ReadRawArray("SelfDamage", animation.SelfDamage, Read);
103
104 if (xml.IsStartElement("Attacks"))
105 {
106 ReadRawArray("Attacks", animation.Attacks, Read);
107 ReadAttackRing();
108 }
109
110 xml.ReadEndElement();
111
112 if (daeReader != null)
113 {
114 daeReader.Read(animation);
115 }
116
117 return animation;
118 }
119
120 private void ReadVelocities()
121 {
122 if (!xml.IsStartElement("Velocities"))
123 return;
124
125 if (xml.SkipEmpty())
126 return;
127
128 xml.ReadStartElement();
129
130 while (xml.IsStartElement())
131 animation.Velocities.Add(xml.ReadElementContentAsVector2());
132
133 xml.ReadEndElement();
134 }
135
136 private void ReadPositions()
137 {
138 var xz = new Vector2();
139
140 if (xml.IsStartElement("PositionOffset"))
141 {
142 xml.ReadStartElement();
143 xz.X = xml.ReadElementContentAsFloat("X", ns);
144 xz.Y = xml.ReadElementContentAsFloat("Z", ns);
145 xml.ReadEndElement();
146 }
147
148 ReadRawArray("Positions", animation.Positions, ReadPosition);
149
150 for (int i = 0; i < animation.Positions.Count; i++)
151 {
152 var position = animation.Positions[i];
153 position.X = xz.X;
154 position.Z = xz.Y;
155 xz += animation.Velocities[i];
156 }
157 }
158
159 private void ReadRotations()
160 {
161 var rotations = animation.Rotations;
162
163 xml.ReadStartElement("Rotations");
164
165 while (xml.IsStartElement())
166 {
167 xml.ReadStartElement("Bone");
168
169 var keys = new List<KeyFrame>();
170
171 int count = 0;
172
173 while (xml.IsStartElement())
174 {
175 string name = xml.LocalName;
176 string[] tokens = xml.ReadElementContentAsString().Split(emptyChars, StringSplitOptions.RemoveEmptyEntries);
177
178 var key = new KeyFrame();
179 key.Duration = XmlConvert.ToByte(tokens[0]);
180
181 switch (name)
182 {
183 case "EKey":
184 animation.FrameSize = 6;
185 key.Rotation.X = XmlConvert.ToSingle(tokens[1]);
186 key.Rotation.Y = XmlConvert.ToSingle(tokens[2]);
187 key.Rotation.Z = XmlConvert.ToSingle(tokens[3]);
188 break;
189
190 case "QKey":
191 animation.FrameSize = 16;
192 key.Rotation.X = XmlConvert.ToSingle(tokens[1]);
193 key.Rotation.Y = XmlConvert.ToSingle(tokens[2]);
194 key.Rotation.Z = XmlConvert.ToSingle(tokens[3]);
195 key.Rotation.W = -XmlConvert.ToSingle(tokens[4]);
196 break;
197
198 default:
199 throw new InvalidDataException(string.Format("Unknonw animation key type '{0}'", name));
200 }
201
202 count += key.Duration;
203 keys.Add(key);
204 }
205
206 if (count != animation.Velocities.Count)
207 throw new InvalidDataException("bad number of frames");
208
209 rotations.Add(keys);
210 xml.ReadEndElement();
211 }
212
213 xml.ReadEndElement();
214 }
215
216 private void ReadHeights()
217 {
218 if (!xml.IsStartElement("Heights"))
219 return;
220
221 if (xml.SkipEmpty())
222 return;
223
224 xml.ReadStartElement();
225
226 while (xml.IsStartElement())
227 animation.Heights.Add(xml.ReadElementContentAsFloat("Height", ns));
228
229 xml.ReadEndElement();
230 }
231
232 private void ReadThrowInfo()
233 {
234 if (!xml.IsStartElement("ThrowSource"))
235 return;
236
237 if (xml.SkipEmpty())
238 return;
239
240 animation.ThrowSource = new ThrowInfo();
241 xml.ReadStartElement("ThrowSource");
242 xml.ReadStartElement("TargetAdjustment");
243 animation.ThrowSource.Position = xml.ReadElementContentAsVector3("Position");
244 animation.ThrowSource.Angle = xml.ReadElementContentAsFloat("Angle", ns);
245 xml.ReadEndElement();
246 animation.ThrowSource.Distance = xml.ReadElementContentAsFloat("Distance", ns);
247 animation.ThrowSource.Type = MetaEnum.Parse<AnimationType>(xml.ReadElementContentAsString("TargetType", ns));
248 xml.ReadEndElement();
249 }
250
251 private void ReadAttackRing()
252 {
253 if (!xml.IsStartElement("AttackRing") && !xml.IsStartElement("HorizontalExtents"))
254 return;
255
256 if (animation.Attacks.Count == 0)
257 {
258 Console.Error.WriteLine("Warning: AttackRing found but no attacks are present, ignoring");
259 xml.Skip();
260 return;
261 }
262
263 xml.ReadStartElement();
264
265 for (int i = 0; i < 36; i++)
266 animation.AttackRing[i] = xml.ReadElementContentAsFloat();
267
268 xml.ReadEndElement();
269 }
270
271 private void ReadPosition(Position position)
272 {
273 xml.ReadStartElement("Position");
274 position.Height = xml.ReadElementContentAsFloat("Height", ns);
275 position.YOffset = xml.ReadElementContentAsFloat("YOffset", ns);
276 xml.ReadEndElement();
277 }
278
279 private void Read(Particle particle)
280 {
281 xml.ReadStartElement("Particle");
282 particle.Start = xml.ReadElementContentAsInt("Start", ns);
283 particle.End = xml.ReadElementContentAsInt("End", ns);
284 particle.Bone = MetaEnum.Parse<Bone>(xml.ReadElementContentAsString("Bone", ns));
285 particle.Name = xml.ReadElementContentAsString("Name", ns);
286 xml.ReadEndElement();
287 }
288
289 private void Read(Sound sound)
290 {
291 xml.ReadStartElement("Sound");
292 sound.Name = xml.ReadElementContentAsString("Name", ns);
293 sound.Start = xml.ReadElementContentAsInt("Start", ns);
294 xml.ReadEndElement();
295 }
296
297 private void Read(Shortcut shortcut)
298 {
299 xml.ReadStartElement("Shortcut");
300 shortcut.FromState = MetaEnum.Parse<AnimationState>(xml.ReadElementContentAsString("FromState", ns));
301 shortcut.Length = xml.ReadElementContentAsInt("Length", ns);
302 shortcut.ReplaceAtomic = (xml.ReadElementContentAsString("ReplaceAtomic", ns) == "yes");
303 xml.ReadEndElement();
304 }
305
306 private void Read(Footstep footstep)
307 {
308 xml.ReadStartElement("Footstep");
309
310 string frame = xml.GetAttribute("Frame");
311
312 if (frame != null)
313 {
314 footstep.Frame = XmlConvert.ToInt32(frame);
315 footstep.Type = MetaEnum.Parse<FootstepType>(xml.GetAttribute("Type"));
316 }
317 else
318 {
319 footstep.Frame = xml.ReadElementContentAsInt("Frame", ns);
320 footstep.Type = MetaEnum.Parse<FootstepType>(xml.ReadElementContentAsString("Type", ns));
321 }
322
323 xml.ReadEndElement();
324 }
325
326 private void Read(Damage damage)
327 {
328 xml.ReadStartElement("Damage");
329 damage.Points = xml.ReadElementContentAsInt("Points", ns);
330 damage.Frame = xml.ReadElementContentAsInt("Frame", ns);
331 xml.ReadEndElement();
332 }
333
334 private void Read(MotionBlur d)
335 {
336 xml.ReadStartElement("MotionBlur");
337 d.Bones = MetaEnum.Parse<BoneMask>(xml.ReadElementContentAsString("Bones", ns));
338 d.Start = xml.ReadElementContentAsInt("Start", ns);
339 d.End = xml.ReadElementContentAsInt("End", ns);
340 d.Lifetime = xml.ReadElementContentAsInt("Lifetime", ns);
341 d.Alpha = xml.ReadElementContentAsInt("Alpha", ns);
342 d.Interval = xml.ReadElementContentAsInt("Interval", ns);
343 xml.ReadEndElement();
344 }
345
346 private void Read(Attack attack)
347 {
348 xml.ReadStartElement("Attack");
349 attack.Start = xml.ReadElementContentAsInt("Start", ns);
350 attack.End = xml.ReadElementContentAsInt("End", ns);
351 attack.Bones = MetaEnum.Parse<BoneMask>(xml.ReadElementContentAsString("Bones", ns));
352 attack.Flags = MetaEnum.Parse<AttackFlags>(xml.ReadElementContentAsString("Flags", ns));
353 attack.Knockback = xml.ReadElementContentAsFloat("Knockback", ns);
354 attack.HitPoints = xml.ReadElementContentAsInt("HitPoints", ns);
355 attack.HitType = MetaEnum.Parse<AnimationType>(xml.ReadElementContentAsString("HitType", ns));
356 attack.HitLength = xml.ReadElementContentAsInt("HitLength", ns);
357 attack.StunLength = xml.ReadElementContentAsInt("StunLength", ns);
358 attack.StaggerLength = xml.ReadElementContentAsInt("StaggerLength", ns);
359
360 if (xml.IsStartElement("Extents"))
361 {
362 ReadRawArray("Extents", attack.Extents, Read);
363
364 if (attack.Extents.Count != attack.End - attack.Start + 1)
365 Console.Error.WriteLine("Error: Attack starting at frame {0} has an incorrect number of extents ({1})", attack.Start, attack.Extents.Count);
366 }
367
368 xml.ReadEndElement();
369 }
370
371 private void Read(AttackExtent extent)
372 {
373 xml.ReadStartElement("Extent");
374 extent.Angle = xml.ReadElementContentAsFloat("Angle", ns);
375 extent.Length = xml.ReadElementContentAsFloat("Length", ns);
376 extent.MinY = xml.ReadElementContentAsFloat("MinY", ns);
377 extent.MaxY = xml.ReadElementContentAsFloat("MaxY", ns);
378 xml.ReadEndElement();
379 }
380
381 private void ReadRawArray<T>(string name, List<T> list, Action<T> elementReader)
382 where T : new()
383 {
384 if (xml.SkipEmpty())
385 return;
386
387 xml.ReadStartElement();
388
389 while (xml.IsStartElement())
390 {
391 T t = new T();
392 elementReader(t);
393 list.Add(t);
394 }
395
396 xml.ReadEndElement();
397 }
398
399 private void ImportDaeAnimation()
400 {
401 string filePath = xml.GetAttribute("Path");
402 bool empty = xml.SkipEmpty();
403
404 if (!empty)
405 {
406 xml.ReadStartElement();
407
408 if (filePath == null)
409 filePath = xml.ReadElementContentAsString("Path", ns);
410 }
411
412 filePath = Path.Combine(basePath, filePath);
413
414 if (!File.Exists(filePath))
415 {
416 Console.Error.WriteLine("Could not find animation import source file '{0}'", filePath);
417 return;
418 }
419
420 Console.WriteLine("Importing {0}", filePath);
421
422 daeReader = new AnimationDaeReader();
423 daeReader.Scene = Dae.Reader.ReadFile(filePath);
424
425 if (!empty)
426 {
427 if (xml.IsStartElement("Start"))
428 daeReader.StartFrame = xml.ReadElementContentAsInt("Start", ns);
429
430 if (xml.IsStartElement("End"))
431 daeReader.EndFrame = xml.ReadElementContentAsInt("End", ns);
432
433 xml.ReadEndElement();
434 }
435 }
436 }
437}
Note: See TracBrowser for help on using the repository browser.