source: OniSplit/Xml/ParticleXmlImporter.cs@ 1160

Last change on this file since 1160 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: 28.0 KB
Line 
1using System;
2using System.Globalization;
3using System.Xml;
4using Oni.Imaging;
5using Oni.Metadata;
6
7namespace Oni.Xml
8{
9 using Oni.Particles;
10
11 internal class ParticleXmlImporter : ParticleXml
12 {
13 #region Private data
14 private XmlReader xml;
15 private Particle particle;
16 #endregion
17
18 public ParticleXmlImporter(XmlReader xml)
19 {
20 this.xml = xml;
21 this.particle = new Particle();
22 }
23
24 public static void Import(XmlReader xml, BinaryWriter writer)
25 {
26 int lengthPosition = writer.Position;
27
28 writer.WriteUInt16(0);
29 writer.WriteUInt16(18);
30
31 var reader = new ParticleXmlImporter(xml);
32 reader.Read();
33 reader.particle.Write(writer);
34
35 int length = writer.Position - lengthPosition;
36 writer.PushPosition(lengthPosition);
37 writer.WriteUInt16(length);
38 writer.PopPosition();
39 }
40
41 public void Read()
42 {
43 ReadOptions();
44 ReadProperties();
45 ReadAppearance();
46 ReadAttractor();
47 ReadVariables();
48 ReadEmitters();
49 ReadEvents();
50 }
51
52 private void ReadOptions()
53 {
54 if (!xml.IsStartElement("Options"))
55 return;
56
57 xml.ReadStartElement();
58
59 while (xml.IsStartElement())
60 {
61 switch (xml.LocalName)
62 {
63 case "DisableDetailLevel":
64 particle.DisableDetailLevel = MetaEnum.Parse<DisableDetailLevel>(xml.ReadElementContentAsString());
65 continue;
66
67 case "Lifetime":
68 particle.Lifetime = ReadValueFloat();
69 continue;
70
71 case "CollisionRadius":
72 particle.CollisionRadius = ReadValueFloat();
73 continue;
74
75 case "FlyBySoundName":
76 particle.FlyBySoundName = xml.ReadElementContentAsString();
77 continue;
78
79 case "AIAlertRadius":
80 particle.AIAlertRadius = xml.ReadElementContentAsFloat();
81 continue;
82
83 case "AIDodgeRadius":
84 particle.AIDodgeRadius = xml.ReadElementContentAsFloat();
85 continue;
86
87 default:
88 if (ReadFlag1() || ReadFlag2())
89 continue;
90 break;
91 }
92
93 throw new FormatException(string.Format("Unknown option {0}", xml.LocalName));
94 }
95
96 xml.ReadEndElement();
97 }
98
99 private void ReadProperties()
100 {
101 if (!xml.IsStartElement("Properties"))
102 return;
103
104 xml.ReadStartElement();
105
106 while (xml.IsStartElement())
107 {
108 if (ReadFlag1())
109 continue;
110
111 throw new FormatException(string.Format("Unknown property {0}", xml.LocalName));
112 }
113
114 xml.ReadEndElement();
115 }
116
117 private void ReadAppearance()
118 {
119 if (!xml.IsStartElement("Appearance"))
120 return;
121
122 Appearance appearance = particle.Appearance;
123
124 xml.ReadStartElement();
125
126 while (xml.IsStartElement())
127 {
128 switch (xml.LocalName)
129 {
130 case "DisplayType":
131 string text = xml.ReadElementContentAsString();
132
133 switch (text)
134 {
135 case "Geometry":
136 particle.Flags1 |= ParticleFlags1.Geometry;
137 break;
138 case "Vector":
139 particle.Flags2 |= ParticleFlags2.Vector;
140 break;
141 case "Decal":
142 particle.Flags2 |= ParticleFlags2.Decal;
143 break;
144 default:
145 particle.SpriteType = MetaEnum.Parse<SpriteType>(text);
146 break;
147 }
148
149 continue;
150
151 case "TexGeom":
152 appearance.TextureName = xml.ReadElementContentAsString();
153 continue;
154
155 case "Scale":
156 appearance.Scale = ReadValueFloat();
157 continue;
158 case "YScale":
159 appearance.YScale = ReadValueFloat();
160 continue;
161 case "Rotation":
162 appearance.Rotation = ReadValueFloat();
163 continue;
164 case "Alpha":
165 appearance.Alpha = ReadValueFloat();
166 continue;
167 case "XOffset":
168 appearance.XOffset = ReadValueFloat();
169 continue;
170 case "XShorten":
171 appearance.XShorten = ReadValueFloat();
172 continue;
173 case "Tint":
174 appearance.Tint = ReadValueColor();
175 continue;
176 case "EdgeFadeMin":
177 appearance.EdgeFadeMin = ReadValueFloat();
178 continue;
179 case "EdgeFadeMax":
180 appearance.EdgeFadeMax = ReadValueFloat();
181 continue;
182 case "MaxContrailDistance":
183 appearance.MaxContrail = ReadValueFloat();
184 continue;
185 case "LensFlareDistance":
186 appearance.LensFlareDistance = ReadValueFloat();
187 continue;
188 case "LensFlareFadeInFrames":
189 appearance.LensFlareFadeInFrames = xml.ReadElementContentAsInt();
190 continue;
191 case "LensFlareFadeOutFrames":
192 appearance.LensFlareFadeOutFrames = xml.ReadElementContentAsInt();
193 continue;
194 case "MaxDecals":
195 appearance.MaxDecals = xml.ReadElementContentAsInt();
196 continue;
197 case "DecalFadeFrames":
198 appearance.DecalFadeFrames = xml.ReadElementContentAsInt();
199 continue;
200 case "DecalWrapAngle":
201 appearance.DecalWrapAngle = ReadValueFloat();
202 continue;
203 default:
204 if (ReadFlag1() || ReadFlag2())
205 continue;
206 break;
207 }
208
209 throw new FormatException(string.Format("Unknown appearance property {0}", xml.LocalName));
210 }
211
212 xml.ReadEndElement();
213 }
214
215 private void ReadAttractor()
216 {
217 if (!xml.IsStartElement("Attractor"))
218 return;
219
220 xml.ReadStartElement();
221
222 Attractor attractor = particle.Attractor;
223
224 while (xml.IsStartElement())
225 {
226 switch (xml.LocalName)
227 {
228 case "Target":
229 attractor.Target = (AttractorTarget)Enum.Parse(typeof(AttractorTarget), xml.ReadElementContentAsString());
230 continue;
231 case "Selector":
232 attractor.Selector = (AttractorSelector)Enum.Parse(typeof(AttractorSelector), xml.ReadElementContentAsString());
233 continue;
234 case "Class":
235 attractor.ClassName = xml.ReadElementContentAsString();
236 continue;
237 case "MaxDistance":
238 attractor.MaxDistance = ReadValueFloat();
239 continue;
240 case "MaxAngle":
241 attractor.MaxAngle = ReadValueFloat();
242 continue;
243 case "AngleSelectMax":
244 attractor.AngleSelectMax = ReadValueFloat();
245 continue;
246 case "AngleSelectMin":
247 attractor.AngleSelectMin = ReadValueFloat();
248 continue;
249 case "AngleSelectWeight":
250 attractor.AngleSelectWeight = ReadValueFloat();
251 continue;
252 }
253
254 throw new FormatException(string.Format("Unknown attractor property {0}", xml.LocalName));
255 }
256
257 xml.ReadEndElement();
258 }
259
260 private void ReadVariables()
261 {
262 if (!xml.IsStartElement("Variables"))
263 return;
264
265 if (xml.IsEmptyElement)
266 {
267 xml.ReadStartElement();
268 }
269 else
270 {
271 xml.ReadStartElement();
272
273 while (xml.IsStartElement())
274 particle.Variables.Add(ReadVariable());
275
276 xml.ReadEndElement();
277 }
278 }
279
280 private Variable ReadVariable()
281 {
282 string typeName = xml.LocalName;
283 string name = xml.GetAttribute("Name");
284
285 switch (typeName)
286 {
287 case "Float":
288 return new Variable(name, StorageType.Float, ReadValueFloat());
289
290 case "Color":
291 return new Variable(name, StorageType.Color, ReadValueColor());
292
293 case "PingPongState":
294 return new Variable(name, StorageType.PingPongState, ReadValueInt());
295
296 default:
297 throw new XmlException(string.Format("Unknown variable type '{0}'", typeName));
298
299 }
300 }
301
302 private void ReadEmitters()
303 {
304 if (!xml.IsStartElement("Emitters"))
305 return;
306
307 if (xml.IsEmptyElement)
308 {
309 xml.ReadStartElement();
310 }
311 else
312 {
313 xml.ReadStartElement();
314
315 while (xml.IsStartElement())
316 particle.Emitters.Add(ReadEmitter());
317
318 xml.ReadEndElement();
319 }
320 }
321
322 private Emitter ReadEmitter()
323 {
324 xml.ReadStartElement();
325
326 Emitter emitter = new Emitter();
327
328 while (xml.IsStartElement())
329 {
330 switch (xml.LocalName)
331 {
332 case "Class":
333 emitter.ParticleClass = xml.ReadElementContentAsString();
334 continue;
335
336 case "Flags":
337 emitter.Flags = MetaEnum.Parse<EmitterFlags>(xml.ReadElementContentAsString());
338 continue;
339
340 case "TurnOffTreshold":
341 emitter.TurnOffTreshold = xml.ReadElementContentAsInt();
342 continue;
343
344 case "Probability":
345 emitter.Probability = (int)(xml.ReadElementContentAsFloat() * 65535.0f);
346 continue;
347
348 case "Copies":
349 emitter.Copies = xml.ReadElementContentAsFloat();
350 continue;
351
352 case "LinkTo":
353 string text = xml.ReadElementContentAsString();
354 if (!string.IsNullOrEmpty(text))
355 {
356 if (text == "this")
357 emitter.LinkTo = 1;
358 else if (text == "link")
359 emitter.LinkTo = 10;
360 else
361 emitter.LinkTo = int.Parse(text, CultureInfo.InvariantCulture) + 2;
362 }
363 continue;
364
365 case "Rate":
366 xml.ReadStartElement();
367 ReadEmitterRate(emitter);
368 xml.ReadEndElement();
369 continue;
370
371 case "Position":
372 xml.ReadStartElement();
373 ReadEmitterPosition(emitter);
374 xml.ReadEndElement();
375 continue;
376
377 case "Speed":
378 xml.ReadStartElement();
379 ReadEmitterSpeed(emitter);
380 xml.ReadEndElement();
381 continue;
382
383 case "Direction":
384 xml.ReadStartElement();
385 ReadEmitterDirection(emitter);
386 xml.ReadEndElement();
387 continue;
388
389 case "Orientation":
390 emitter.OrientationDir = MetaEnum.Parse<EmitterOrientation>(xml.ReadElementContentAsString());
391 continue;
392
393 case "OrientationUp":
394 emitter.OrientationUp = MetaEnum.Parse<EmitterOrientation>(xml.ReadElementContentAsString());
395 continue;
396 }
397
398 throw new FormatException(string.Format("Unknown emitter property '{0}'", xml.LocalName));
399 }
400
401 xml.ReadEndElement();
402
403 return emitter;
404 }
405
406 private void ReadEmitterRate(Emitter emitter)
407 {
408 emitter.Rate = MetaEnum.Parse<EmitterRate>(xml.LocalName);
409
410 if (xml.IsEmptyElement)
411 {
412 xml.ReadStartElement();
413 }
414 else
415 {
416 xml.ReadStartElement();
417
418 switch (emitter.Rate)
419 {
420 case EmitterRate.Continous:
421 emitter.Parameters[0] = ReadValueFloat("Interval");
422 break;
423 case EmitterRate.Random:
424 emitter.Parameters[0] = ReadValueFloat("MinInterval");
425 emitter.Parameters[1] = ReadValueFloat("MaxInterval");
426 break;
427 case EmitterRate.Distance:
428 emitter.Parameters[0] = ReadValueFloat("Distance");
429 break;
430 case EmitterRate.Attractor:
431 emitter.Parameters[0] = ReadValueFloat("RechargeTime");
432 emitter.Parameters[1] = ReadValueFloat("CheckInterval");
433 break;
434
435 }
436
437 xml.ReadEndElement();
438 }
439 }
440
441 private void ReadEmitterPosition(Emitter emitter)
442 {
443 emitter.Position = MetaEnum.Parse<EmitterPosition>(xml.LocalName);
444
445 if (xml.IsEmptyElement)
446 {
447 xml.ReadStartElement();
448 }
449 else
450 {
451 xml.ReadStartElement();
452
453 switch (emitter.Position)
454 {
455 case EmitterPosition.Line:
456 emitter.Parameters[2] = ReadValueFloat("Radius");
457 break;
458 case EmitterPosition.Circle:
459 case EmitterPosition.Sphere:
460 emitter.Parameters[2] = ReadValueFloat("InnerRadius");
461 emitter.Parameters[3] = ReadValueFloat("OuterRadius");
462 break;
463 case EmitterPosition.Offset:
464 emitter.Parameters[2] = ReadValueFloat("X");
465 emitter.Parameters[3] = ReadValueFloat("Y");
466 emitter.Parameters[4] = ReadValueFloat("Z");
467 break;
468 case EmitterPosition.Cylinder:
469 emitter.Parameters[2] = ReadValueFloat("Height");
470 emitter.Parameters[3] = ReadValueFloat("InnerRadius");
471 emitter.Parameters[4] = ReadValueFloat("OuterRadius");
472 break;
473 case EmitterPosition.BodySurface:
474 case EmitterPosition.BodyBones:
475 emitter.Parameters[2] = ReadValueFloat("OffsetRadius");
476 break;
477 }
478
479 xml.ReadEndElement();
480 }
481 }
482
483 private void ReadEmitterDirection(Emitter emitter)
484 {
485 emitter.Direction = MetaEnum.Parse<EmitterDirection>(xml.LocalName);
486
487 if (xml.IsEmptyElement)
488 {
489 xml.ReadStartElement();
490 }
491 else
492 {
493 xml.ReadStartElement();
494
495 switch (emitter.Direction)
496 {
497 case EmitterDirection.Cone:
498 emitter.Parameters[5] = ReadValueFloat("Angle");
499 emitter.Parameters[6] = ReadValueFloat("CenterBias");
500 break;
501 case EmitterDirection.Ring:
502 emitter.Parameters[5] = ReadValueFloat("Angle");
503 emitter.Parameters[6] = ReadValueFloat("Offset");
504 break;
505 case EmitterDirection.Offset:
506 emitter.Parameters[5] = ReadValueFloat("X");
507 emitter.Parameters[6] = ReadValueFloat("Y");
508 emitter.Parameters[7] = ReadValueFloat("Z");
509 break;
510 case EmitterDirection.Inaccurate:
511 emitter.Parameters[5] = ReadValueFloat("BaseAngle");
512 emitter.Parameters[6] = ReadValueFloat("Inaccuracy");
513 emitter.Parameters[7] = ReadValueFloat("CenterBias");
514 break;
515 }
516
517 xml.ReadEndElement();
518 }
519 }
520
521 private void ReadEmitterSpeed(Emitter emitter)
522 {
523 emitter.Speed = MetaEnum.Parse<EmitterSpeed>(xml.LocalName);
524
525 if (xml.IsEmptyElement)
526 {
527 xml.ReadStartElement();
528 }
529 else
530 {
531 xml.ReadStartElement();
532
533 switch (emitter.Speed)
534 {
535 case EmitterSpeed.Uniform:
536 emitter.Parameters[8] = ReadValueFloat("Speed");
537 break;
538 case EmitterSpeed.Stratified:
539 emitter.Parameters[8] = ReadValueFloat("Speed1");
540 emitter.Parameters[9] = ReadValueFloat("Speed2");
541 break;
542 }
543
544 xml.ReadEndElement();
545 }
546 }
547
548 private void ReadEvents()
549 {
550 if (!xml.IsStartElement("Events"))
551 return;
552
553 if (xml.IsEmptyElement)
554 {
555 xml.ReadStartElement();
556 }
557 else
558 {
559 xml.ReadStartElement();
560
561 while (xml.IsStartElement())
562 ReadEvent();
563
564 xml.ReadEndElement();
565 }
566 }
567
568 private void ReadEvent()
569 {
570 Event e = new Event((EventType)Enum.Parse(typeof(EventType), xml.LocalName));
571
572 if (xml.IsEmptyElement)
573 {
574 xml.ReadStartElement();
575 }
576 else
577 {
578 xml.ReadStartElement();
579
580 while (xml.IsStartElement())
581 e.Actions.Add(ReadEventAction());
582
583 xml.ReadEndElement();
584 }
585
586 particle.Events.Add(e);
587 }
588
589 private EventAction ReadEventAction()
590 {
591 EventAction action = new EventAction((EventActionType)Enum.Parse(typeof(EventActionType), xml.LocalName));
592 EventActionInfo info = eventActionInfoTable[(int)action.Type];
593
594 if (xml.IsEmptyElement)
595 {
596 xml.ReadStartElement();
597 }
598 else
599 {
600 xml.ReadStartElement();
601
602 for (int i = 0; xml.IsStartElement(); i++)
603 {
604 if (i < info.OutCount)
605 {
606 action.Variables.Add(new VariableReference(xml.ReadElementContentAsString()));
607 continue;
608 }
609
610 if (i >= info.Parameters.Length)
611 throw new XmlException(string.Format("Too many arguments for action '{0}'", action.Type));
612
613 switch (info.Parameters[i].Type)
614 {
615 case StorageType.Float:
616 case StorageType.BlastFalloff:
617 action.Parameters.Add(ReadValueFloat());
618 continue;
619
620 case StorageType.Color:
621 action.Parameters.Add(ReadValueColor());
622 continue;
623
624 case StorageType.ActionIndex:
625 case StorageType.Emitter:
626 case StorageType.CoordFrame:
627 case StorageType.CollisionOrient:
628 case StorageType.Boolean:
629 case StorageType.PingPongState:
630 case StorageType.ImpactModifier:
631 case StorageType.DamageType:
632 case StorageType.Direction:
633 action.Parameters.Add(ReadValueInt());
634 continue;
635
636 case StorageType.ImpulseSoundName:
637 case StorageType.AmbientSoundName:
638 case StorageType.ImpactName:
639 action.Parameters.Add(ReadValueInstance());
640 continue;
641 }
642 }
643
644 xml.ReadEndElement();
645 }
646
647 return action;
648 }
649
650 private Value ReadValueInstance()
651 {
652 return new Value(ValueType.InstanceName, xml.ReadElementContentAsString());
653 }
654
655 private Value ReadValueInt()
656 {
657 Value value = null;
658 xml.ReadStartElement();
659
660 string text = xml.ReadElementContentAsString();
661 int i;
662
663 if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out i))
664 value = new Value(i);
665 else
666 value = new Value(ValueType.Variable, text.Trim());
667
668 xml.ReadEndElement();
669 return value;
670 }
671
672 private Value ReadValueFloat(string name)
673 {
674 if (xml.LocalName != name)
675 throw new XmlException(string.Format(CultureInfo.CurrentCulture, "Unexpected '{0}' element found at line {1}", xml.LocalName, 0));
676
677 return ReadValueFloat();
678 }
679
680 private Value ReadValueFloat()
681 {
682 if (xml.IsEmptyElement)
683 {
684 xml.Read();
685 return new Value(0.0f);
686 }
687
688 Value value = null;
689
690 xml.ReadStartElement();
691
692 if (xml.NodeType == XmlNodeType.Text)
693 {
694 string text = xml.ReadElementContentAsString();
695 float f;
696
697 if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out f))
698 value = new Value(f);
699 else
700 value = new Value(ValueType.Variable, text.Trim());
701 }
702 else if (xml.NodeType == XmlNodeType.Element)
703 {
704 string name = xml.LocalName;
705
706 if (name == "Random")
707 {
708 float min = float.Parse(xml.GetAttribute("Min"), CultureInfo.InvariantCulture);
709 float max = float.Parse(xml.GetAttribute("Max"), CultureInfo.InvariantCulture);
710 value = new Value(ValueType.FloatRandom, min, max);
711 }
712 else if (name == "BellCurve")
713 {
714 float mean = float.Parse(xml.GetAttribute("Mean"), CultureInfo.InvariantCulture);
715 float stddev = float.Parse(xml.GetAttribute("StdDev"), CultureInfo.InvariantCulture);
716 value = new Value(ValueType.FloatBellCurve, mean, stddev);
717 }
718 else
719 {
720 throw new XmlException(string.Format(CultureInfo.CurrentCulture, "Unknown value type '{0}'", name));
721 }
722
723 xml.ReadStartElement();
724 }
725
726 xml.ReadEndElement();
727 return value;
728 }
729
730 private Value ReadValueColor()
731 {
732 Value value = null;
733
734 xml.ReadStartElement();
735
736 if (xml.NodeType == XmlNodeType.Text)
737 {
738 string text = xml.ReadElementContentAsString();
739 Color c;
740
741 if (Color.TryParse(text, out c))
742 value = new Value(c);
743 else
744 value = new Value(ValueType.Variable, text.Trim());
745 }
746 else if (xml.NodeType == XmlNodeType.Element)
747 {
748 string name = xml.LocalName;
749
750 if (name == "Random")
751 {
752 Color min = Color.Parse(xml.GetAttribute("Min"));
753 Color max = Color.Parse(xml.GetAttribute("Max"));
754 value = new Value(ValueType.ColorRandom, min, max);
755 }
756 else if (name == "BellCurve")
757 {
758 Color mean = Color.Parse(xml.GetAttribute("Mean"));
759 Color stddev = Color.Parse(xml.GetAttribute("StdDev"));
760 value = new Value(ValueType.ColorBellCurve, mean, stddev);
761 }
762 else
763 {
764 throw new XmlException(string.Format(CultureInfo.CurrentCulture, "Unknown value type '{0}'", name));
765 }
766
767 xml.ReadStartElement();
768 }
769
770 xml.ReadEndElement();
771 return value;
772 }
773
774 private bool ReadFlag1()
775 {
776 ParticleFlags1 flag;
777
778 try
779 {
780 flag = (ParticleFlags1)Enum.Parse(typeof(ParticleFlags1), xml.LocalName);
781 }
782 catch
783 {
784 return false;
785 }
786
787 if (ReadFlagValue())
788 particle.Flags1 |= flag;
789
790 return true;
791 }
792
793 private bool ReadFlag2()
794 {
795 ParticleFlags2 flag;
796
797 try
798 {
799 flag = (ParticleFlags2)Enum.Parse(typeof(ParticleFlags2), xml.LocalName);
800 }
801 catch
802 {
803 return false;
804 }
805
806 if (ReadFlagValue())
807 particle.Flags2 |= flag;
808
809 return true;
810 }
811
812 private bool ReadFlagValue()
813 {
814 string text = xml.ReadElementContentAsString();
815
816 switch (text)
817 {
818 case "false":
819 return false;
820 case "true":
821 return true;
822 default:
823 throw new FormatException(string.Format(CultureInfo.CurrentCulture, "Unknown value '{0}'", text));
824 }
825 }
826 }
827}
Note: See TracBrowser for help on using the repository browser.