MonoGameModelTemplate.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Graphics;
  6. using MODELMESH = SharpGLTF.Runtime.Template.RuntimeModelMesh;
  7. namespace SharpGLTF.Runtime.Template
  8. {
  9. public class MonoGameModelTemplate
  10. {
  11. #region lifecycle
  12. internal MonoGameModelTemplate(SceneTemplate[] scenes, int defaultSceneIndex, IReadOnlyDictionary<int, MODELMESH> meshes)
  13. {
  14. _Meshes = meshes;
  15. _Effects = _Meshes.Values
  16. .SelectMany(item => item.Effects)
  17. .Distinct()
  18. .ToArray();
  19. _Scenes = scenes;
  20. #pragma warning disable GLTFRT1000 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
  21. _Bounds = scenes.Select(item => new BoundingSphere(item.SphereBounds.center, item.SphereBounds.radius)).ToArray();
  22. #pragma warning restore GLTFRT1000 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
  23. /*
  24. _Bounds = scenes
  25. .Select(item => CalculateBounds(item))
  26. .ToArray();*/
  27. _DefaultSceneIndex = defaultSceneIndex;
  28. }
  29. #endregion
  30. #region data
  31. /// <summary>
  32. /// Meshes shared by all the scenes.
  33. /// </summary>
  34. internal readonly IReadOnlyDictionary<int, MODELMESH> _Meshes;
  35. /// <summary>
  36. /// Effects shared by all the meshes.
  37. /// </summary>
  38. private readonly Effect[] _Effects;
  39. private readonly SceneTemplate[] _Scenes;
  40. private readonly BoundingSphere[] _Bounds;
  41. private readonly int _DefaultSceneIndex;
  42. #endregion
  43. #region properties
  44. public int SceneCount => _Scenes.Length;
  45. public IReadOnlyList<Effect> Effects => _Effects;
  46. public BoundingSphere Bounds => GetBounds(_DefaultSceneIndex);
  47. #endregion
  48. #region API
  49. public int IndexOfScene(string sceneName) => Array.FindIndex(_Scenes, item => item.Name == sceneName);
  50. public BoundingSphere GetBounds(int sceneIndex) => _Bounds[sceneIndex];
  51. /// <summary>
  52. /// Creates an instance from the default model's scene.
  53. /// </summary>
  54. /// <returns>A model instance.</returns>
  55. public MonoGameModelInstance CreateInstance() => CreateInstance(_DefaultSceneIndex);
  56. /// <summary>
  57. /// Creates an instance from the given model scene.
  58. /// </summary>
  59. /// <param name="sceneIndex">The scene index.</param>
  60. /// <returns>A model instance.</returns>
  61. public MonoGameModelInstance CreateInstance(int sceneIndex)
  62. {
  63. return new MonoGameModelInstance(this, _Scenes[sceneIndex].CreateInstance());
  64. }
  65. private BoundingSphere CalculateBounds(SceneTemplate scene)
  66. {
  67. var instances = scene.CreateInstance();
  68. var bounds = default(BoundingSphere);
  69. foreach (var inst in instances)
  70. {
  71. var b = _Meshes[inst.Template.LogicalMeshIndex].BoundingSphere;
  72. System.Diagnostics.Debug.Assert(b.Radius > 0);
  73. switch(inst.Transform)
  74. {
  75. case Transforms.RigidTransform statXform:
  76. b = b.Transform(statXform.WorldMatrix);
  77. break;
  78. case Transforms.SkinnedTransform skinXform:
  79. // this is a bit agressive and probably over-reaching, but with skins you
  80. // never know the actual bounds unless you calculate them frame by frame.
  81. var bb = b;
  82. foreach (var xb in skinXform.SkinMatrices.Select(item => bb.Transform(item)))
  83. {
  84. b = BoundingSphere.CreateMerged(b, xb);
  85. }
  86. break;
  87. }
  88. bounds = bounds.Radius == 0 ? b : BoundingSphere.CreateMerged(bounds, b);
  89. }
  90. return bounds;
  91. }
  92. #endregion
  93. #region shared lights and effects
  94. public void ConfigureLightsAndFog(Action<IEffectLights> configureLights, Action<IEffectFog> configureFog)
  95. {
  96. configureLights ??= l => l.EnableDefaultLighting();
  97. configureFog ??= f => f.FogEnabled = false;
  98. foreach (var mesh in _Meshes.Values)
  99. {
  100. foreach (var effect in _Effects)
  101. {
  102. if (effect is IEffectLights lights)
  103. {
  104. configureLights.Invoke(lights);
  105. }
  106. if (effect is IEffectFog fog)
  107. {
  108. configureFog.Invoke(fog);
  109. }
  110. }
  111. }
  112. }
  113. #endregion
  114. }
  115. }