ParticleEffectWriter.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. using System;
  2. using System.IO;
  3. using System.Xml;
  4. using MonoGame.Extended.Graphics;
  5. using MonoGame.Extended.Particles.Data;
  6. using MonoGame.Extended.Particles.Modifiers;
  7. using MonoGame.Extended.Particles.Modifiers.Containers;
  8. using MonoGame.Extended.Particles.Modifiers.Interpolators;
  9. using MonoGame.Extended.Particles.Profiles;
  10. using MonoGame.Extended.Serialization.Xml;
  11. namespace MonoGame.Extended.Particles;
  12. /// <summary>
  13. /// Represents a writer that serializes a <see cref="ParticleEffect"/> to an XML configuration.
  14. /// </summary>
  15. public class ParticleEffectWriter : IDisposable
  16. {
  17. private readonly XmlWriter _writer;
  18. /// <summary>
  19. /// Gets a value that indicates if this <see cref="ParticleEffectWriter"/> has been disposed of.
  20. /// </summary>
  21. public bool IsDisposed { get; private set; }
  22. /// <summary>
  23. /// Initializes a new instance of the <see cref="ParticleEffectWriter"/> class that writers to the writes to a file.
  24. /// </summary>
  25. /// <param name="fileName">The file path to write the XML to.</param>
  26. public ParticleEffectWriter(string fileName)
  27. {
  28. XmlWriterSettings settings = new XmlWriterSettings();
  29. settings.Indent = true;
  30. settings.IndentChars = " ";
  31. settings.CloseOutput = true;
  32. settings.NewLineChars = "\n";
  33. _writer = XmlWriter.Create(fileName, settings);
  34. }
  35. /// <summary>
  36. /// Initializes a new instance of the <see cref="ParticleEffectWriter"/> class that writes to a stream.
  37. /// </summary>
  38. /// <param name="stream">The stream to write to.</param>
  39. public ParticleEffectWriter(Stream stream)
  40. {
  41. XmlWriterSettings settings = new XmlWriterSettings();
  42. settings.Indent = true;
  43. settings.IndentChars = " ";
  44. settings.CloseOutput = false;
  45. settings.NewLineChars = "\n";
  46. _writer = XmlWriter.Create(stream, settings);
  47. }
  48. /// <summary/>
  49. ~ParticleEffectWriter()
  50. {
  51. Dispose();
  52. }
  53. /// <summary>
  54. /// Write a <see cref="ParticleEffect"/> to the XML output.
  55. /// </summary>
  56. /// <param name="effect">The <see cref="ParticleEffect"/> to serialize.</param>
  57. /// <exception cref="ArgumentNullException"><paramref name="effect"/> is <see langword="null"/>.</exception>
  58. public void WriteParticleEffect(ParticleEffect effect)
  59. {
  60. ArgumentNullException.ThrowIfNull(effect);
  61. _writer.WriteStartDocument();
  62. _writer.WriteStartElement("ParticleEffect");
  63. _writer.WriteAttributeString(nameof(ParticleEffect.Name), effect.Name);
  64. _writer.WriteAttributeVector2(nameof(ParticleEffect.Position), effect.Position);
  65. _writer.WriteAttributeFloat(nameof(ParticleEffect.Rotation), effect.Rotation);
  66. _writer.WriteAttributeVector2(nameof(ParticleEffect.Scale), effect.Scale);
  67. _writer.WriteAttributeBool(nameof(ParticleEffect.AutoTrigger), effect.AutoTrigger);
  68. _writer.WriteAttributeFloat(nameof(ParticleEffect.AutoTriggerFrequency), effect.AutoTriggerFrequency);
  69. if (effect.Emitters.Count > 0)
  70. {
  71. _writer.WriteStartElement(nameof(ParticleEffect.Emitters));
  72. foreach (ParticleEmitter emitter in effect.Emitters)
  73. {
  74. _writer.WriteStartElement(nameof(ParticleEmitter));
  75. WriteParticleEmitter(emitter);
  76. _writer.WriteEndElement();
  77. }
  78. _writer.WriteEndElement();
  79. }
  80. _writer.WriteEndElement();
  81. _writer.WriteEndDocument();
  82. _writer.Flush();
  83. }
  84. private void WriteParticleEmitter(ParticleEmitter emitter)
  85. {
  86. _writer.WriteAttributeString(nameof(ParticleEmitter.Name), emitter.Name);
  87. _writer.WriteAttributeFloat(nameof(ParticleEmitter.LifeSpan), emitter.LifeSpan);
  88. _writer.WriteAttributeVector2(nameof(ParticleEmitter.Offset), emitter.Offset);
  89. _writer.WriteAttributeFloat(nameof(ParticleEmitter.LayerDepth), emitter.LayerDepth);
  90. _writer.WriteAttributeFloat(nameof(ParticleEmitter.ReclaimFrequency), emitter.ReclaimFrequency);
  91. _writer.WriteAttributeInt(nameof(ParticleEmitter.Capacity), emitter.Capacity);
  92. _writer.WriteAttributeString(nameof(ParticleEmitter.ModifierExecutionStrategy), emitter.ModifierExecutionStrategy.ToString());
  93. _writer.WriteAttributeString(nameof(ParticleEmitter.RenderingOrder), emitter.RenderingOrder.ToString());
  94. if (emitter.TextureRegion is Texture2DRegion region)
  95. {
  96. _writer.WriteStartElement(nameof(ParticleEmitter.TextureRegion));
  97. WriteTexture2DRegion(region);
  98. _writer.WriteEndElement();
  99. }
  100. _writer.WriteStartElement(nameof(ParticleEmitter.Parameters));
  101. WriteParticleReleaseParameters(emitter.Parameters);
  102. _writer.WriteEndElement();
  103. _writer.WriteStartElement(nameof(ParticleEmitter.Profile));
  104. WriteProfile(emitter.Profile);
  105. _writer.WriteEndElement();
  106. if (emitter.Modifiers.Count > 0)
  107. {
  108. _writer.WriteStartElement(nameof(ParticleEmitter.Modifiers));
  109. foreach (Modifier modifier in emitter.Modifiers)
  110. {
  111. _writer.WriteStartElement(nameof(Modifier));
  112. WriteModifier(modifier);
  113. _writer.WriteEndElement();
  114. }
  115. _writer.WriteEndElement();
  116. }
  117. }
  118. private void WriteTexture2DRegion(Texture2DRegion region)
  119. {
  120. _writer.WriteAttributeString(nameof(Texture2DRegion.Texture.Name), region.Texture.Name);
  121. _writer.WriteAttributeRectangle(nameof(Texture2DRegion.Bounds), region.Bounds);
  122. }
  123. private void WriteParticleReleaseParameters(ParticleReleaseParameters parameters)
  124. {
  125. WriteParticleInt32Parameter(nameof(ParticleReleaseParameters.Quantity), parameters.Quantity);
  126. WriteParticleFloatParameter(nameof(ParticleReleaseParameters.Speed), parameters.Speed);
  127. WriteParticleColorParameter(nameof(ParticleReleaseParameters.Color), parameters.Color);
  128. WriteParticleFloatParameter(nameof(ParticleReleaseParameters.Opacity), parameters.Opacity);
  129. WriteParticleVector2Parameter(nameof(ParticleReleaseParameters.Scale), parameters.Scale);
  130. WriteParticleFloatParameter(nameof(ParticleReleaseParameters.Rotation), parameters.Rotation);
  131. WriteParticleFloatParameter(nameof(ParticleReleaseParameters.Mass), parameters.Mass);
  132. }
  133. private void WriteParticleInt32Parameter(string name, ParticleInt32Parameter parameter)
  134. {
  135. _writer.WriteStartElement(name);
  136. _writer.WriteAttributeString(nameof(ParticleInt32Parameter.Kind), parameter.Kind.ToString());
  137. if (parameter.Kind == ParticleValueKind.Constant)
  138. {
  139. _writer.WriteAttributeInt(nameof(ParticleInt32Parameter.Constant), parameter.Constant);
  140. }
  141. else
  142. {
  143. _writer.WriteAttributeInt(nameof(ParticleInt32Parameter.RandomMin), parameter.RandomMin);
  144. _writer.WriteAttributeInt(nameof(ParticleInt32Parameter.RandomMax), parameter.RandomMax);
  145. }
  146. _writer.WriteEndElement();
  147. }
  148. private void WriteParticleFloatParameter(string name, ParticleFloatParameter parameter)
  149. {
  150. _writer.WriteStartElement(name);
  151. _writer.WriteAttributeString(nameof(ParticleFloatParameter.Kind), parameter.Kind.ToString());
  152. if (parameter.Kind == ParticleValueKind.Constant)
  153. {
  154. _writer.WriteAttributeFloat(nameof(ParticleFloatParameter.Constant), parameter.Constant);
  155. }
  156. else
  157. {
  158. _writer.WriteAttributeFloat(nameof(ParticleFloatParameter.RandomMin), parameter.RandomMin);
  159. _writer.WriteAttributeFloat(nameof(ParticleFloatParameter.RandomMax), parameter.RandomMax);
  160. }
  161. _writer.WriteEndElement();
  162. }
  163. private void WriteParticleVector2Parameter(string name, ParticleVector2Parameter parameter)
  164. {
  165. _writer.WriteStartElement(name);
  166. _writer.WriteAttributeString(nameof(ParticleVector2Parameter.Kind), parameter.Kind.ToString());
  167. if(parameter.Kind == ParticleValueKind.Constant)
  168. {
  169. _writer.WriteAttributeVector2(nameof(ParticleVector2Parameter.Constant), parameter.Constant);
  170. }
  171. else
  172. {
  173. _writer.WriteAttributeVector2(nameof(ParticleVector2Parameter.RandomMin), parameter.RandomMin);
  174. _writer.WriteAttributeVector2(nameof(ParticleVector2Parameter.RandomMax), parameter.RandomMax);
  175. }
  176. _writer.WriteEndElement();
  177. }
  178. private void WriteParticleColorParameter(string name, ParticleColorParameter parameter)
  179. {
  180. _writer.WriteStartElement(name);
  181. _writer.WriteAttributeString(nameof(ParticleColorParameter.Kind), parameter.Kind.ToString());
  182. if (parameter.Kind == ParticleValueKind.Constant)
  183. {
  184. _writer.WriteAttributeVector3(nameof(ParticleColorParameter.Constant), parameter.Constant);
  185. }
  186. else
  187. {
  188. _writer.WriteAttributeVector3(nameof(ParticleColorParameter.RandomMin), parameter.RandomMin);
  189. _writer.WriteAttributeVector3(nameof(ParticleColorParameter.RandomMax), parameter.RandomMax);
  190. }
  191. _writer.WriteEndElement();
  192. }
  193. private void WriteProfile(Profile profile)
  194. {
  195. switch (profile)
  196. {
  197. case BoxFillProfile boxFillProfile:
  198. _writer.WriteAttributeString(nameof(Type), nameof(BoxFillProfile));
  199. _writer.WriteAttributeFloat(nameof(BoxFillProfile.Width), boxFillProfile.Width);
  200. _writer.WriteAttributeFloat(nameof(BoxFillProfile.Height), boxFillProfile.Height);
  201. break;
  202. case BoxProfile boxProfile:
  203. _writer.WriteAttributeString(nameof(Type), nameof(BoxProfile));
  204. _writer.WriteAttributeFloat(nameof(BoxProfile.Width), boxProfile.Width);
  205. _writer.WriteAttributeFloat(nameof(BoxProfile.Height), boxProfile.Height);
  206. break;
  207. case BoxUniformProfile boxUniformProfile:
  208. _writer.WriteAttributeString(nameof(Type), nameof(BoxUniformProfile));
  209. _writer.WriteAttributeFloat(nameof(BoxUniformProfile.Width), boxUniformProfile.Width);
  210. _writer.WriteAttributeFloat(nameof(BoxUniformProfile.Height), boxUniformProfile.Height);
  211. break;
  212. case CircleProfile circleProfile:
  213. _writer.WriteAttributeString(nameof(Type), nameof(CircleProfile));
  214. _writer.WriteAttributeFloat(nameof(CircleProfile.Radius), circleProfile.Radius);
  215. _writer.WriteAttributeString(nameof(CircleProfile.Radiate), circleProfile.Radiate.ToString());
  216. break;
  217. case LineProfile lineProfile:
  218. _writer.WriteAttributeString(nameof(Type), nameof(LineProfile));
  219. _writer.WriteAttributeVector2(nameof(LineProfile.Axis), lineProfile.Axis);
  220. _writer.WriteAttributeFloat(nameof(LineProfile.Length), lineProfile.Length);
  221. break;
  222. case PointProfile:
  223. _writer.WriteAttributeString(nameof(Type), nameof(PointProfile));
  224. break;
  225. case RingProfile ringProfile:
  226. _writer.WriteAttributeString(nameof(Type), nameof(RingProfile));
  227. _writer.WriteAttributeFloat(nameof(RingProfile.Radius), ringProfile.Radius);
  228. _writer.WriteAttributeString(nameof(RingProfile.Radiate), ringProfile.Radiate.ToString());
  229. break;
  230. case SprayProfile sprayProfile:
  231. _writer.WriteAttributeString(nameof(Type), nameof(SprayProfile));
  232. _writer.WriteAttributeVector2(nameof(SprayProfile.Direction), sprayProfile.Direction);
  233. _writer.WriteAttributeFloat(nameof(SprayProfile.Spread), sprayProfile.Spread);
  234. break;
  235. default:
  236. _writer.WriteAttributeString(nameof(Type), nameof(PointProfile));
  237. break;
  238. }
  239. }
  240. private void WriteModifier(Modifier modifier)
  241. {
  242. _writer.WriteAttributeString(nameof(Modifier.Name), modifier.Name);
  243. _writer.WriteAttributeFloat(nameof(Modifier.Frequency), modifier.Frequency);
  244. switch (modifier)
  245. {
  246. case AgeModifier ageModifier:
  247. _writer.WriteAttributeString(nameof(Type), nameof(AgeModifier));
  248. if (ageModifier.Interpolators.Count > 0)
  249. {
  250. _writer.WriteStartElement(nameof(AgeModifier.Interpolators));
  251. foreach (Interpolator interpolator in ageModifier.Interpolators)
  252. {
  253. _writer.WriteStartElement(nameof(Interpolator));
  254. WriteInterpolator(interpolator);
  255. _writer.WriteEndElement();
  256. }
  257. _writer.WriteEndElement();
  258. }
  259. break;
  260. case CircleContainerModifier circleContainerModifier:
  261. _writer.WriteAttributeString(nameof(Type), nameof(CircleContainerModifier));
  262. _writer.WriteAttributeFloat(nameof(CircleContainerModifier.Radius), circleContainerModifier.Radius);
  263. _writer.WriteAttributeBool(nameof(CircleContainerModifier.Inside), circleContainerModifier.Inside);
  264. _writer.WriteAttributeFloat(nameof(CircleContainerModifier.RestitutionCoefficient), circleContainerModifier.RestitutionCoefficient);
  265. break;
  266. case DragModifier dragModifier:
  267. _writer.WriteAttributeString(nameof(Type), nameof(DragModifier));
  268. _writer.WriteAttributeFloat(nameof(DragModifier.DragCoefficient), dragModifier.DragCoefficient);
  269. _writer.WriteAttributeFloat(nameof(DragModifier.Density), dragModifier.Density);
  270. break;
  271. case LinearGravityModifier linearGravityModifier:
  272. _writer.WriteAttributeString(nameof(Type), nameof(LinearGravityModifier));
  273. _writer.WriteAttributeVector2(nameof(LinearGravityModifier.Direction), linearGravityModifier.Direction);
  274. _writer.WriteAttributeFloat(nameof(LinearGravityModifier.Strength), linearGravityModifier.Strength);
  275. break;
  276. case OpacityFastFadeModifier:
  277. _writer.WriteAttributeString(nameof(Type), nameof(OpacityFastFadeModifier));
  278. break;
  279. case RectangleContainerModifier rectangleContainerModifier:
  280. _writer.WriteAttributeString(nameof(Type), nameof(RectangleContainerModifier));
  281. _writer.WriteAttributeInt(nameof(RectangleContainerModifier.Width), rectangleContainerModifier.Width);
  282. _writer.WriteAttributeInt(nameof(RectangleContainerModifier.Height), rectangleContainerModifier.Height);
  283. _writer.WriteAttributeFloat(nameof(RectangleContainerModifier.RestitutionCoefficient), rectangleContainerModifier.RestitutionCoefficient);
  284. break;
  285. case RectangleLoopContainerModifier rectangleLoopContainerModifier:
  286. _writer.WriteAttributeString(nameof(Type), nameof(RectangleLoopContainerModifier));
  287. _writer.WriteAttributeInt(nameof(RectangleLoopContainerModifier.Width), rectangleLoopContainerModifier.Width);
  288. _writer.WriteAttributeInt(nameof(RectangleLoopContainerModifier.Height), rectangleLoopContainerModifier.Height);
  289. break;
  290. case RotationModifier rotationModifier:
  291. _writer.WriteAttributeString(nameof(Type), nameof(RotationModifier));
  292. _writer.WriteAttributeFloat(nameof(RotationModifier.RotationRate), rotationModifier.RotationRate);
  293. break;
  294. case VelocityColorModifier velocityColorModifier:
  295. _writer.WriteAttributeString(nameof(Type), nameof(VelocityColorModifier));
  296. _writer.WriteAttributeVector3(nameof(VelocityColorModifier.StationaryColor), velocityColorModifier.StationaryColor);
  297. _writer.WriteAttributeVector3(nameof(VelocityColorModifier.VelocityColor), velocityColorModifier.VelocityColor);
  298. _writer.WriteAttributeFloat(nameof(VelocityColorModifier.VelocityThreshold), velocityColorModifier.VelocityThreshold);
  299. break;
  300. case VelocityModifier velocityModifier:
  301. _writer.WriteAttributeString(nameof(Type), nameof(VelocityModifier));
  302. _writer.WriteAttributeFloat(nameof(VelocityModifier.VelocityThreshold), velocityModifier.VelocityThreshold);
  303. if (velocityModifier.Interpolators.Count > 0)
  304. {
  305. _writer.WriteStartElement(nameof(VelocityModifier.Interpolators));
  306. foreach (Interpolator interpolator in velocityModifier.Interpolators)
  307. {
  308. _writer.WriteStartElement(nameof(Interpolator));
  309. WriteInterpolator(interpolator);
  310. _writer.WriteEndElement();
  311. }
  312. _writer.WriteEndElement();
  313. }
  314. break;
  315. case VortexModifier vortexModifier:
  316. _writer.WriteAttributeString(nameof(Type), nameof(VortexModifier));
  317. _writer.WriteAttributeVector2(nameof(VortexModifier.Position), vortexModifier.Position);
  318. _writer.WriteAttributeFloat(nameof(VortexModifier.Mass), vortexModifier.Mass);
  319. _writer.WriteAttributeFloat(nameof(VortexModifier.MaxSpeed), vortexModifier.MaxSpeed);
  320. break;
  321. default:
  322. _writer.WriteAttributeString(nameof(Type), "Unknown");
  323. break;
  324. }
  325. }
  326. private void WriteInterpolator(Interpolator interpolator)
  327. {
  328. _writer.WriteAttributeString(nameof(interpolator.Name), interpolator.Name);
  329. switch (interpolator)
  330. {
  331. case ColorInterpolator colorInterpolator:
  332. _writer.WriteAttributeString(nameof(Type), nameof(ColorInterpolator));
  333. _writer.WriteAttributeVector3(nameof(ColorInterpolator.StartValue), colorInterpolator.StartValue);
  334. _writer.WriteAttributeVector3(nameof(ColorInterpolator.EndValue), colorInterpolator.EndValue);
  335. break;
  336. case HueInterpolator hueInterpolator:
  337. _writer.WriteAttributeString(nameof(Type), nameof(HueInterpolator));
  338. _writer.WriteAttributeFloat(nameof(HueInterpolator.StartValue), hueInterpolator.StartValue);
  339. _writer.WriteAttributeFloat(nameof(HueInterpolator.EndValue), hueInterpolator.EndValue);
  340. break;
  341. case OpacityInterpolator opacityInterpolator:
  342. _writer.WriteAttributeString(nameof(Type), nameof(OpacityInterpolator));
  343. _writer.WriteAttributeFloat(nameof(OpacityInterpolator.StartValue), opacityInterpolator.StartValue);
  344. _writer.WriteAttributeFloat(nameof(OpacityInterpolator.EndValue), opacityInterpolator.EndValue);
  345. break;
  346. case RotationInterpolator rotationInterpolator:
  347. _writer.WriteAttributeString(nameof(Type), nameof(RotationInterpolator));
  348. _writer.WriteAttributeFloat(nameof(RotationInterpolator.StartValue), rotationInterpolator.StartValue);
  349. _writer.WriteAttributeFloat(nameof(RotationInterpolator.EndValue), rotationInterpolator.EndValue);
  350. break;
  351. case ScaleInterpolator scaleInterpolator:
  352. _writer.WriteAttributeString(nameof(Type), nameof(ScaleInterpolator));
  353. _writer.WriteAttributeVector2(nameof(ScaleInterpolator.StartValue), scaleInterpolator.StartValue);
  354. _writer.WriteAttributeVector2(nameof(ScaleInterpolator.EndValue), scaleInterpolator.EndValue);
  355. break;
  356. case VelocityInterpolator velocityInterpolator:
  357. _writer.WriteAttributeString(nameof(Type), nameof(VelocityInterpolator));
  358. _writer.WriteAttributeVector2(nameof(VelocityInterpolator.StartValue), velocityInterpolator.StartValue);
  359. _writer.WriteAttributeVector2(nameof(VelocityInterpolator.EndValue), velocityInterpolator.EndValue);
  360. break;
  361. default:
  362. _writer.WriteAttributeString(nameof(Type), "Unknown");
  363. break;
  364. }
  365. }
  366. /// <inheritdoc/>
  367. public void Dispose()
  368. {
  369. if (IsDisposed)
  370. {
  371. return;
  372. }
  373. _writer.Dispose();
  374. GC.SuppressFinalize(this);
  375. IsDisposed = true;
  376. }
  377. }