| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Graphics;
- using MODELMESH = SharpGLTF.Runtime.Template.RuntimeModelMesh;
- namespace SharpGLTF.Runtime.Template
- {
- public class MonoGameModelTemplate
- {
- #region lifecycle
-
- internal MonoGameModelTemplate(SceneTemplate[] scenes, int defaultSceneIndex, IReadOnlyDictionary<int, MODELMESH> meshes)
- {
- _Meshes = meshes;
- _Effects = _Meshes.Values
- .SelectMany(item => item.Effects)
- .Distinct()
- .ToArray();
- _Scenes = scenes;
- #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.
- _Bounds = scenes.Select(item => new BoundingSphere(item.SphereBounds.center, item.SphereBounds.radius)).ToArray();
- #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.
- /*
- _Bounds = scenes
- .Select(item => CalculateBounds(item))
- .ToArray();*/
- _DefaultSceneIndex = defaultSceneIndex;
- }
- #endregion
- #region data
-
- /// <summary>
- /// Meshes shared by all the scenes.
- /// </summary>
- internal readonly IReadOnlyDictionary<int, MODELMESH> _Meshes;
- /// <summary>
- /// Effects shared by all the meshes.
- /// </summary>
- private readonly Effect[] _Effects;
- private readonly SceneTemplate[] _Scenes;
- private readonly BoundingSphere[] _Bounds;
- private readonly int _DefaultSceneIndex;
- #endregion
- #region properties
- public int SceneCount => _Scenes.Length;
- public IReadOnlyList<Effect> Effects => _Effects;
- public BoundingSphere Bounds => GetBounds(_DefaultSceneIndex);
-
- #endregion
- #region API
- public int IndexOfScene(string sceneName) => Array.FindIndex(_Scenes, item => item.Name == sceneName);
- public BoundingSphere GetBounds(int sceneIndex) => _Bounds[sceneIndex];
- /// <summary>
- /// Creates an instance from the default model's scene.
- /// </summary>
- /// <returns>A model instance.</returns>
- public MonoGameModelInstance CreateInstance() => CreateInstance(_DefaultSceneIndex);
- /// <summary>
- /// Creates an instance from the given model scene.
- /// </summary>
- /// <param name="sceneIndex">The scene index.</param>
- /// <returns>A model instance.</returns>
- public MonoGameModelInstance CreateInstance(int sceneIndex)
- {
- return new MonoGameModelInstance(this, _Scenes[sceneIndex].CreateInstance());
- }
- private BoundingSphere CalculateBounds(SceneTemplate scene)
- {
- var instances = scene.CreateInstance();
- var bounds = default(BoundingSphere);
- foreach (var inst in instances)
- {
- var b = _Meshes[inst.Template.LogicalMeshIndex].BoundingSphere;
- System.Diagnostics.Debug.Assert(b.Radius > 0);
- switch(inst.Transform)
- {
- case Transforms.RigidTransform statXform:
- b = b.Transform(statXform.WorldMatrix);
- break;
- case Transforms.SkinnedTransform skinXform:
- // this is a bit agressive and probably over-reaching, but with skins you
- // never know the actual bounds unless you calculate them frame by frame.
- var bb = b;
- foreach (var xb in skinXform.SkinMatrices.Select(item => bb.Transform(item)))
- {
- b = BoundingSphere.CreateMerged(b, xb);
- }
- break;
- }
- bounds = bounds.Radius == 0 ? b : BoundingSphere.CreateMerged(bounds, b);
- }
- return bounds;
- }
- #endregion
- #region shared lights and effects
-
- public void ConfigureLightsAndFog(Action<IEffectLights> configureLights, Action<IEffectFog> configureFog)
- {
- configureLights ??= l => l.EnableDefaultLighting();
- configureFog ??= f => f.FogEnabled = false;
- foreach (var mesh in _Meshes.Values)
- {
- foreach (var effect in _Effects)
- {
- if (effect is IEffectLights lights)
- {
- configureLights.Invoke(lights);
- }
- if (effect is IEffectFog fog)
- {
- configureFog.Invoke(fog);
- }
- }
- }
- }
- #endregion
- }
- }
|