浏览代码

Moving *Template classes to *Content (WIP)

vpenades 4 年之前
父节点
当前提交
910f40d644
共有 23 个文件被更改,包括 379 次插入629 次删除
  1. 1 1
      src/MonoScene.Pipeline.Assimp/AssimpModelFactory.cs
  2. 2 2
      src/MonoScene.Pipeline.Assimp/Factories/ArmatureFactory.Assimp.cs
  3. 3 2
      src/MonoScene.Pipeline.GLTF/Converters.cs
  4. 2 2
      src/MonoScene.Pipeline.GLTF/Factories/ArmatureFactory.GLTF.cs
  5. 1 1
      src/MonoScene.Pipeline.GLTF/GltfModelFactory.cs
  6. 10 8
      src/MonoScene.Pipeline/ArmatureFactory.cs
  7. 2 2
      src/MonoScene.Pipeline/ModelCollectionContent.cs
  8. 76 77
      src/MonoScene.Runtime.Content/AnimatableProperty.cs
  9. 9 6
      src/MonoScene.Runtime.Content/Materials/MaterialContent.cs
  10. 19 17
      src/MonoScene.Runtime.Content/Materials/SamplerStateContent.cs
  11. 2 6
      src/MonoScene.Runtime.Content/Meshes/MeshContent.cs
  12. 0 295
      src/MonoScene.Runtime.Content/Meshes/MeshDecoder.cs
  13. 3 2
      src/MonoScene.Runtime.Content/Model/AnimationTrackInfo.cs
  14. 10 7
      src/MonoScene.Runtime.Content/Model/ArmatureContent.cs
  15. 120 0
      src/MonoScene.Runtime.Content/Model/NodeContent.cs
  16. 2 6
      src/MonoScene.Runtime.Content/MonoScene.Runtime.Content.csproj
  17. 5 3
      src/MonoScene.Runtime.Model3D/ModelGraph/ArmatureInstance.cs
  18. 5 3
      src/MonoScene.Runtime.Model3D/ModelGraph/DrawableTemplate.cs
  19. 6 3
      src/MonoScene.Runtime.Model3D/ModelGraph/ModelCollection.cs
  20. 9 8
      src/MonoScene.Runtime.Model3D/ModelGraph/ModelTemplate.cs
  21. 84 0
      src/MonoScene.Runtime.Model3D/ModelGraph/NodeContent.Evaluator.cs
  22. 8 3
      src/MonoScene.Runtime.Model3D/ModelGraph/NodeInstance.cs
  23. 0 175
      src/MonoScene.Runtime.Model3D/ModelGraph/NodeTemplate.cs

+ 1 - 1
src/MonoScene.Pipeline.Assimp/AssimpModelFactory.cs

@@ -63,7 +63,7 @@ namespace MonoScene.Graphics.Pipeline
             // build the armatures and models
             // build the armatures and models
 
 
             var models = new List<ModelTemplate>();
             var models = new List<ModelTemplate>();
-            var armatures = new List<ArmatureTemplate>();
+            var armatures = new List<ArmatureContent>();
 
 
             var armatureFactory = new AssimpArmatureFactory(scene);
             var armatureFactory = new AssimpArmatureFactory(scene);
             var armature = armatureFactory.CreateArmature();
             var armature = armatureFactory.CreateArmature();

+ 2 - 2
src/MonoScene.Pipeline.Assimp/Factories/ArmatureFactory.Assimp.cs

@@ -44,14 +44,14 @@ namespace MonoScene.Graphics.Pipeline
 
 
         #region API
         #region API
 
 
-        public ModelTemplate CreateModel(Assimp.Scene scene, ArmatureTemplate armature, IReadOnlyList<IMeshDecoder<MaterialContent>> meshDecoders)
+        public ModelTemplate CreateModel(Assimp.Scene scene, ArmatureContent armature, IReadOnlyList<IMeshDecoder<MaterialContent>> meshDecoders)
         {
         {
             var model = CreateModel(scene, armature);
             var model = CreateModel(scene, armature);
             model.ModelBounds = MeshFactory.EvaluateBoundingSphere(model.CreateInstance(), meshDecoders);
             model.ModelBounds = MeshFactory.EvaluateBoundingSphere(model.CreateInstance(), meshDecoders);
             return model;
             return model;
         }
         }
 
 
-        public ModelTemplate CreateModel(Assimp.Scene scene, ArmatureTemplate armature)
+        public ModelTemplate CreateModel(Assimp.Scene scene, ArmatureContent armature)
         {
         {
             var drawables = Flatten(scene.RootNode)
             var drawables = Flatten(scene.RootNode)
                 .Where(item => item.HasMeshes)
                 .Where(item => item.HasMeshes)

+ 3 - 2
src/MonoScene.Pipeline.GLTF/Converters.cs

@@ -73,10 +73,11 @@ namespace MonoScene.Graphics.Pipeline
             return TextureFilter.Linear; // fallback
             return TextureFilter.Linear; // fallback
         }
         }
 
 
-        public static MaterialContent ToXna(this GLTFMATERIAL srcMaterial)
+        public static MaterialContent ToXna(this GLTFMATERIAL srcMaterial, Converter<SharpGLTF.Schema2.ExtraProperties, Object> tagConverter)
         {
         {
             var dstMaterial = new MaterialContent();
             var dstMaterial = new MaterialContent();
             dstMaterial.Name = srcMaterial.Name;
             dstMaterial.Name = srcMaterial.Name;
+            dstMaterial.Tag = tagConverter?.Invoke(srcMaterial);
 
 
             dstMaterial.DoubleSided = srcMaterial.DoubleSided;
             dstMaterial.DoubleSided = srcMaterial.DoubleSided;
 
 
@@ -138,7 +139,7 @@ namespace MonoScene.Graphics.Pipeline
             var srcMaterials = srcMeshes.First().LogicalParent.LogicalMaterials;
             var srcMaterials = srcMeshes.First().LogicalParent.LogicalMaterials;
 
 
             var dstMaterials = srcMaterials
             var dstMaterials = srcMaterials
-                .Select(item => item.ToXna())
+                .Select(item => item.ToXna(tagConverter))
                 .ToArray();
                 .ToArray();
 
 
             var dstMeshes = srcMeshes
             var dstMeshes = srcMeshes

+ 2 - 2
src/MonoScene.Pipeline.GLTF/Factories/ArmatureFactory.GLTF.cs

@@ -108,14 +108,14 @@ namespace MonoScene.Graphics.Pipeline
 
 
         #region API
         #region API
 
 
-        public ModelTemplate CreateModel(SharpGLTF.Schema2.Scene scene, ArmatureTemplate armature, IReadOnlyList<IMeshDecoder<MaterialContent>> meshDecoders)
+        public ModelTemplate CreateModel(SharpGLTF.Schema2.Scene scene, ArmatureContent armature, IReadOnlyList<IMeshDecoder<MaterialContent>> meshDecoders)
         {
         {
             var model = CreateModel(scene, armature);
             var model = CreateModel(scene, armature);
             model.ModelBounds = MeshFactory.EvaluateBoundingSphere(model.CreateInstance(), meshDecoders);
             model.ModelBounds = MeshFactory.EvaluateBoundingSphere(model.CreateInstance(), meshDecoders);
             return model;
             return model;
         }
         }
 
 
-        public ModelTemplate CreateModel(SharpGLTF.Schema2.Scene scene, ArmatureTemplate armature)
+        public ModelTemplate CreateModel(SharpGLTF.Schema2.Scene scene, ArmatureContent armature)
         {
         {
             var drawables = GLTFNODE.Flatten(scene)
             var drawables = GLTFNODE.Flatten(scene)
                 .Where(item => item.Mesh != null)
                 .Where(item => item.Mesh != null)

+ 1 - 1
src/MonoScene.Pipeline.GLTF/GltfModelFactory.cs

@@ -104,7 +104,7 @@ namespace MonoScene.Graphics.Pipeline
 
 
             // build the armatures and models
             // build the armatures and models
 
 
-            var armatures = new List<ArmatureTemplate>();
+            var armatures = new List<ArmatureContent>();
             var models = new List<ModelTemplate>();
             var models = new List<ModelTemplate>();
 
 
             foreach (var scene in srcModel.LogicalScenes)
             foreach (var scene in srcModel.LogicalScenes)

+ 10 - 8
src/MonoScene.Pipeline/ArmatureFactory.cs

@@ -3,6 +3,8 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 
 
+using MonoScene.Graphics.Content;
+
 using XNAV3 = Microsoft.Xna.Framework.Vector3;
 using XNAV3 = Microsoft.Xna.Framework.Vector3;
 using XNAMAT = Microsoft.Xna.Framework.Matrix;
 using XNAMAT = Microsoft.Xna.Framework.Matrix;
 using XNAQUAT = Microsoft.Xna.Framework.Quaternion;
 using XNAQUAT = Microsoft.Xna.Framework.Quaternion;
@@ -14,8 +16,8 @@ namespace MonoScene.Graphics.Pipeline
         #region data
         #region data
 
 
         private readonly List<AnimationTrackInfo> _AnimationTracks = new List<AnimationTrackInfo>();
         private readonly List<AnimationTrackInfo> _AnimationTracks = new List<AnimationTrackInfo>();
-        private readonly List<NodeTemplate> _Nodes = new List<NodeTemplate>();
-        private readonly Dictionary<TNode, NodeTemplate> _Map = new Dictionary<TNode, NodeTemplate>();
+        private readonly List<NodeContent> _Nodes = new List<NodeContent>();
+        private readonly Dictionary<TNode, NodeContent> _Map = new Dictionary<TNode, NodeContent>();
 
 
         #endregion
         #endregion
 
 
@@ -37,12 +39,12 @@ namespace MonoScene.Graphics.Pipeline
         protected abstract Object GetTag(TNode node);
         protected abstract Object GetTag(TNode node);
         protected abstract IEnumerable<TNode> GetChildren(TNode node);
         protected abstract IEnumerable<TNode> GetChildren(TNode node);
         protected abstract XNAMAT GetLocalMatrix(TNode node);
         protected abstract XNAMAT GetLocalMatrix(TNode node);
-        protected abstract AnimatableProperty<XNAV3> GetScale(TNode node);
-        protected abstract AnimatableProperty<XNAQUAT> GetRotation(TNode node);
-        protected abstract AnimatableProperty<XNAV3> GetTranslation(TNode node);
+        protected abstract Content.AnimatableProperty<XNAV3> GetScale(TNode node);
+        protected abstract Content.AnimatableProperty<XNAQUAT> GetRotation(TNode node);
+        protected abstract Content.AnimatableProperty<XNAV3> GetTranslation(TNode node);
 
 
 
 
-        public NodeTemplate GetNode(TNode srcNode) => _Map[srcNode];
+        public NodeContent GetNode(TNode srcNode) => _Map[srcNode];
 
 
         public IDrawableTemplate CreateRigidDrawable(int meshIndex, TNode node)
         public IDrawableTemplate CreateRigidDrawable(int meshIndex, TNode node)
         {
         {
@@ -62,7 +64,7 @@ namespace MonoScene.Graphics.Pipeline
             return d;
             return d;
         }
         }
 
 
-        public ArmatureTemplate CreateArmature() { return new ArmatureTemplate(_Nodes.ToArray(), _AnimationTracks.ToArray()); }
+        public ArmatureContent CreateArmature() { return new ArmatureContent(_Nodes.ToArray(), _AnimationTracks.ToArray()); }
 
 
         #endregion
         #endregion
 
 
@@ -86,7 +88,7 @@ namespace MonoScene.Graphics.Pipeline
                 childIndices.Add(childIndex);
                 childIndices.Add(childIndex);
             }
             }
             
             
-            var dst = new NodeTemplate(thisIdx, parentIndex, childIndices.ToArray());
+            var dst = new NodeContent(thisIdx, parentIndex, childIndices.ToArray());
             dst.Name = GetName(src);
             dst.Name = GetName(src);
             dst.Tag = GetTag(src);
             dst.Tag = GetTag(src);
 
 

+ 2 - 2
src/MonoScene.Pipeline/ModelCollectionContent.cs

@@ -13,7 +13,7 @@ namespace MonoScene.Graphics.Pipeline
     {
     {
         #region constructor
         #region constructor
 
 
-        public ModelCollectionContent(MeshCollectionContent meshes, ArmatureTemplate[] armatures, ModelTemplate[] models, int defaultModelIndex)
+        public ModelCollectionContent(MeshCollectionContent meshes, ArmatureContent[] armatures, ModelTemplate[] models, int defaultModelIndex)
         {
         {
             _SharedMeshes = meshes;
             _SharedMeshes = meshes;
             _SharedArmatures = armatures;
             _SharedArmatures = armatures;
@@ -33,7 +33,7 @@ namespace MonoScene.Graphics.Pipeline
         /// <summary>
         /// <summary>
         /// Multiple <see cref="ModelTemplate"/> at <see cref="_Models"/> might share the same <see cref="ArmatureTemplate"/>.
         /// Multiple <see cref="ModelTemplate"/> at <see cref="_Models"/> might share the same <see cref="ArmatureTemplate"/>.
         /// </summary>
         /// </summary>
-        private ArmatureTemplate[] _SharedArmatures;
+        private ArmatureContent[] _SharedArmatures;
 
 
         /// <summary>
         /// <summary>
         /// Models available in this collection.
         /// Models available in this collection.

+ 76 - 77
src/MonoScene.Runtime.Model3D/AnimatableProperty.cs → src/MonoScene.Runtime.Content/AnimatableProperty.cs

@@ -1,77 +1,76 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MonoScene
-{
-    /// <summary>
-    /// Defines an animatable property with a default value and a collection of animation curve tracks.
-    /// </summary>
-    /// <typeparam name="T">A type that can be interpolated with <see cref="ICurveEvaluator{T}"/></typeparam>
-    [System.Diagnostics.DebuggerDisplay("{Value} with {CurveCount} curves.")]
-    public sealed class AnimatableProperty<T>
-       where T : struct
-    {
-        #region lifecycle
-
-        public AnimatableProperty(T defaultValue)
-        {
-            Value = defaultValue;
-        }
-
-        #endregion
-
-        #region data
-
-        private List<Microsoft.Xna.Framework.ICurveEvaluator<T>> _Curves;
-
-        /// <summary>
-        /// Gets the default value of this instance.
-        /// When animations are disabled, or there's no animation track available, this will be the returned value.
-        /// </summary>
-        public T Value { get; set; }
-
-        #endregion
-
-        #region properties
-
-        public bool IsAnimated => _Curves == null ? false : _Curves.Count > 0;
-
-        public int CurveCount => _Curves.Count;
-
-        #endregion
-
-        #region API
-
-        /// <summary>
-        /// Evaluates the value of this <see cref="AnimatableProperty{T}"/> at a given <paramref name="offset"/> for a given <paramref name="curveIndex"/>.
-        /// </summary>
-        /// <param name="curveIndex">The index of the animation track</param>
-        /// <param name="offset">The time offset within the curve</param>
-        /// <returns>The evaluated value taken from the animation <paramref name="curveIndex"/>, or <see cref="Value"/> if a track was not found.</returns>
-        public T GetValueAt(int curveIndex, float offset)
-        {
-            if (_Curves == null) return this.Value;
-
-            if (curveIndex < 0 || curveIndex >= _Curves.Count) return this.Value;
-
-            return _Curves[curveIndex]?.Evaluate(offset) ?? this.Value;
-        }
-
-        public void SetCurve(int curveIndex, Microsoft.Xna.Framework.ICurveEvaluator<T> sampler)
-        {
-            if (curveIndex < 0) throw new ArgumentOutOfRangeException(nameof(curveIndex));
-            if (sampler == null) throw new ArgumentNullException(nameof(sampler));
-
-            if (_Curves == null) _Curves = new List<Microsoft.Xna.Framework.ICurveEvaluator<T>>();
-
-            while (_Curves.Count <= curveIndex) _Curves.Add(null);
-
-            _Curves[curveIndex] = sampler;
-        }
-
-        #endregion
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MonoScene.Graphics.Content
+{
+    /// <summary>
+    /// Defines an animatable property with a default value and a collection of animation curve tracks.
+    /// </summary>
+    /// <typeparam name="T">A type that can be interpolated with <see cref="ICurveEvaluator{T}"/></typeparam>
+    [System.Diagnostics.DebuggerDisplay("{Value} with {CurveCount} curves.")]
+    public sealed class AnimatableProperty<T>
+       where T : struct
+    {
+        #region lifecycle
+
+        public AnimatableProperty(T defaultValue)
+        {
+            Value = defaultValue;
+        }
+
+        #endregion
+
+        #region data
+
+        private List<Microsoft.Xna.Framework.ICurveEvaluator<T>> _Curves;
+
+        /// <summary>
+        /// Gets the default value of this instance.
+        /// When animations are disabled, or there's no animation track available, this will be the returned value.
+        /// </summary>
+        public T Value { get; set; }
+
+        #endregion
+
+        #region properties
+
+        public bool IsAnimated => _Curves == null ? false : _Curves.Count > 0;
+
+        public int CurveCount => _Curves.Count;
+
+        #endregion
+
+        #region API
+
+        /// <summary>
+        /// Evaluates the value of this <see cref="AnimatableProperty{T}"/> at a given <paramref name="offset"/> for a given <paramref name="curveIndex"/>.
+        /// </summary>
+        /// <param name="curveIndex">The index of the animation track</param>
+        /// <param name="offset">The time offset within the curve</param>
+        /// <returns>The evaluated value taken from the animation <paramref name="curveIndex"/>, or <see cref="Value"/> if a track was not found.</returns>
+        public T GetValueAt(int curveIndex, float offset)
+        {
+            if (_Curves == null) return this.Value;
+
+            if (curveIndex < 0 || curveIndex >= _Curves.Count) return this.Value;
+
+            return _Curves[curveIndex]?.Evaluate(offset) ?? this.Value;
+        }
+
+        public void SetCurve(int curveIndex, Microsoft.Xna.Framework.ICurveEvaluator<T> sampler)
+        {
+            if (curveIndex < 0) throw new ArgumentOutOfRangeException(nameof(curveIndex));
+
+            if (_Curves == null) _Curves = new List<Microsoft.Xna.Framework.ICurveEvaluator<T>>();
+
+            while (_Curves.Count <= curveIndex) _Curves.Add(null);
+
+            _Curves[curveIndex] = sampler ?? throw new ArgumentNullException(nameof(sampler));
+        }
+
+        #endregion
+    }
+}

+ 9 - 6
src/MonoScene.Runtime.Content/Materials/MaterialContent.cs

@@ -5,8 +5,16 @@ using System.Text;
 
 
 namespace MonoScene.Graphics.Content
 namespace MonoScene.Graphics.Content
 {
 {
+    /// <summary>
+    /// Represents a material, defined as a collection of <see cref="MaterialChannelContent"/> elements.
+    /// </summary>
+    /// <remarks>
+    /// Unlike MonoGame's native <see cref="Microsoft.Xna.Framework.Graphics.Model"/>,<br/>
+    /// this material architecture does not store any <see cref="Microsoft.Xna.Framework.Graphics.Effect"/>,<br/>
+    /// which must be created and assigned at load time.
+    /// </remarks>
     [System.Diagnostics.DebuggerDisplay("{Name} - {TargetEffectName}")]
     [System.Diagnostics.DebuggerDisplay("{Name} - {TargetEffectName}")]
-    public class MaterialContent
+    public class MaterialContent : BaseContent
     {
     {
         #region lifecycle
         #region lifecycle
         public MaterialContent() { }
         public MaterialContent() { }
@@ -21,11 +29,6 @@ namespace MonoScene.Graphics.Content
         #endregion
         #endregion
 
 
         #region properties
         #region properties
-
-        /// <summary>
-        /// The name of this material, or NULL
-        /// </summary>
-        public string Name { get; set; }
         
         
         /// <summary>
         /// <summary>
         /// This defined the shading profile for this material. Loading from glTF we can find:
         /// This defined the shading profile for this material. Loading from glTF we can find:

+ 19 - 17
src/MonoScene.Runtime.Content/Materials/SamplerStateContent.cs

@@ -2,7 +2,9 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 
 
-using Microsoft.Xna.Framework.Graphics;
+using TEXFILTER = Microsoft.Xna.Framework.Graphics.TextureFilter;
+using TEXADDRESS = Microsoft.Xna.Framework.Graphics.TextureAddressMode;
+using TEXSAMPLER = Microsoft.Xna.Framework.Graphics.SamplerState;
 
 
 namespace MonoScene.Graphics.Content
 namespace MonoScene.Graphics.Content
 {
 {
@@ -22,14 +24,14 @@ namespace MonoScene.Graphics.Content
             };
             };
         }
         }
 
 
-        public TextureFilter Filter { get; set; }
-        public TextureAddressMode AddressU { get; set; }
-        public TextureAddressMode AddressV { get; set; }
-        public TextureAddressMode AddressW { get; set; }
+        public TEXFILTER Filter { get; set; }
+        public TEXADDRESS AddressU { get; set; }
+        public TEXADDRESS AddressV { get; set; }
+        public TEXADDRESS AddressW { get; set; }
 
 
-        public SamplerState CreateState()
+        public TEXSAMPLER CreateState()
         {
         {
-            return new SamplerState()
+            return new TEXSAMPLER()
             {
             {
                 Filter = this.Filter,
                 Filter = this.Filter,
                 AddressU = this.AddressU,
                 AddressU = this.AddressU,
@@ -38,26 +40,26 @@ namespace MonoScene.Graphics.Content
             };
             };
         }
         }
 
 
-        public SamplerState TryGetPredefinedSampler()
+        public TEXSAMPLER TryGetPredefinedSampler()
         {
         {
             if (AddressU != AddressV) return null;
             if (AddressU != AddressV) return null;
 
 
-            if (Filter == TextureFilter.Point)
+            if (Filter == TEXFILTER.Point)
             {
             {
-                if (AddressU == TextureAddressMode.Clamp) return SamplerState.PointClamp;
-                if (AddressU == TextureAddressMode.Wrap) return SamplerState.PointWrap;
+                if (AddressU == TEXADDRESS.Clamp) return TEXSAMPLER.PointClamp;
+                if (AddressU == TEXADDRESS.Wrap) return TEXSAMPLER.PointWrap;
             }
             }
 
 
-            if (Filter == TextureFilter.Linear)
+            if (Filter == TEXFILTER.Linear)
             {
             {
-                if (AddressU == TextureAddressMode.Clamp) return SamplerState.LinearClamp;
-                if (AddressU == TextureAddressMode.Wrap) return SamplerState.LinearWrap;
+                if (AddressU == TEXADDRESS.Clamp) return TEXSAMPLER.LinearClamp;
+                if (AddressU == TEXADDRESS.Wrap) return TEXSAMPLER.LinearWrap;
             }
             }
 
 
-            if (Filter == TextureFilter.Anisotropic)
+            if (Filter == TEXFILTER.Anisotropic)
             {
             {
-                if (AddressU == TextureAddressMode.Clamp) return SamplerState.AnisotropicClamp;
-                if (AddressU == TextureAddressMode.Wrap) return SamplerState.AnisotropicWrap;
+                if (AddressU == TEXADDRESS.Clamp) return TEXSAMPLER.AnisotropicClamp;
+                if (AddressU == TEXADDRESS.Wrap) return TEXSAMPLER.AnisotropicWrap;
             }
             }
 
 
             return null;
             return null;

+ 2 - 6
src/MonoScene.Runtime.Content/Meshes/MeshContent.cs

@@ -73,13 +73,9 @@ namespace MonoScene.Graphics.Content
     /// <summary>
     /// <summary>
     /// Represents a Mesh, made of multiple <see cref="MeshPartContent"/>
     /// Represents a Mesh, made of multiple <see cref="MeshPartContent"/>
     /// </summary>
     /// </summary>
-    public class MeshContent
+    public class MeshContent : BaseContent
     {
     {
-        private readonly List<MeshPartContent> _Primitives = new List<MeshPartContent>();
-
-        public string Name { get; set; }
-
-        public Object Tag { get; set; }
+        private readonly List<MeshPartContent> _Primitives = new List<MeshPartContent>();        
 
 
         public IReadOnlyList<MeshPartContent> Parts => _Primitives;
         public IReadOnlyList<MeshPartContent> Parts => _Primitives;
 
 

+ 0 - 295
src/MonoScene.Runtime.Content/Meshes/MeshDecoder.cs

@@ -1,295 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Graphics.PackedVector;
-
-using XY = Microsoft.Xna.Framework.Vector2;
-using XYZ = Microsoft.Xna.Framework.Vector3;
-using XYZW = Microsoft.Xna.Framework.Vector4;
-
-namespace Microsoft.Xna.Framework.Content.Runtime.Graphics
-{
-    /// <summary>
-    /// Interface used by importers to create a proxy mesh that wraps the native format mesh.
-    /// </summary>
-    /// <typeparam name="TMaterial"></typeparam>
-    public interface IMeshDecoder<TMaterial>
-        where TMaterial : class
-    {
-        string Name { get; }
-        Object Tag { get; }
-        IReadOnlyList<IMeshPrimitiveDecoder<TMaterial>> Primitives { get; }        
-    }    
-
-    public interface IMeshPrimitiveDecoder<TMaterial> : IMeshPrimitiveDecoder
-        where TMaterial : class
-    {
-        TMaterial Material { get; }
-    }
-
-    public interface IMeshPrimitiveDecoder
-    {
-        #region properties
-
-        /// <summary>
-        /// Gets a value indicating the total number of vertices for this primitive.
-        /// </summary>
-        int VertexCount { get; }
-
-        /// <summary>
-        /// Gets a value indicating the total number of morph targets for this primitive.
-        /// </summary>
-        int MorphTargetsCount { get; }
-
-        /// <summary>
-        /// Gets a value indicating the number of color vertex attributes.
-        /// In the range of 0 to 2.
-        /// </summary>
-        int ColorsCount { get; }
-
-        /// <summary>
-        /// Gets a value indicating the number of texture coordinate vertex attributes.
-        /// In the range of 0 to 2.
-        /// </summary>
-        int TexCoordsCount { get; }
-
-        /// <summary>
-        /// Gets a value indicating the number of skinning joint-weight attributes.
-        /// The values can be 0, 4 or 8.
-        /// </summary>
-        int JointsWeightsCount { get; }
-
-        /// <summary>
-        /// Gets a sequence of tuples where each item represents the vertex indices of a line.
-        /// </summary>
-        IEnumerable<(int A, int B)> LineIndices { get; }
-
-        /// <summary>
-        /// Gets a sequence of tuples where each item represents the vertex indices of a triangle.
-        /// </summary>
-        IEnumerable<(int A, int B, int C)> TriangleIndices { get; }
-
-        #endregion
-
-        #region API
-
-        XYZ GetPosition(int vertexIndex);
-
-        XYZ GetNormal(int vertexIndex);
-
-        XYZW GetTangent(int vertexIndex);
-
-        IReadOnlyList<XYZ> GetPositionDeltas(int vertexIndex);
-
-        IReadOnlyList<XYZ> GetNormalDeltas(int vertexIndex);
-
-        IReadOnlyList<XYZ> GetTangentDeltas(int vertexIndex);
-
-        XY GetTextureCoord(int vertexIndex, int textureSetIndex);
-
-        XYZW GetColor(int vertexIndex, int colorSetIndex);
-
-        VertexInfluences GetSkinWeights(int vertexIndex);
-
-        #endregion
-    }
-
-    
-
-    static class MeshPrimitiveDecoder
-    {
-        public static VertexDeclaration GetVertexDeclaration(this IMeshPrimitiveDecoder src)
-        {
-            // because the PBR shaders have a limited number of techniques,
-            // we require adding these attributes even if they're not used.
-            var nColors = Math.Max(src.ColorsCount, 1);
-            var nTextrs = Math.Max(src.TexCoordsCount, 2);
-
-            var e = new List<VertexElement>();
-            int offset = 0;
-
-            e.Add(new VertexElement(offset, VertexElementFormat.Vector3, VertexElementUsage.Position, 0)); offset += 12;
-            e.Add(new VertexElement(offset, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)); offset += 12;
-            e.Add(new VertexElement(offset, VertexElementFormat.Vector4, VertexElementUsage.Tangent, 0)); offset += 16;            
-
-            for(int i=0; i < nColors; ++i)
-            {
-                e.Add(new VertexElement(offset, VertexElementFormat.Color, VertexElementUsage.Color, i)); offset += 4;
-            }            
-
-            for (int i = 0; i < nTextrs; ++i)
-            {
-                e.Add(new VertexElement(offset, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, i)); offset += 8;
-            }
-
-            if (src.JointsWeightsCount > 0)
-            {
-                e.Add(new VertexElement(offset, VertexElementFormat.Short4, VertexElementUsage.BlendIndices, 0)); offset += 8;
-                e.Add(new VertexElement(offset, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0)); offset += 16;
-            }
-
-            return new VertexDeclaration(e.ToArray());
-        }
-
-        public static Byte[] ToXnaVertices(this IMeshPrimitiveDecoder src, VertexDeclaration decl)
-        {
-            var dst = new Byte[src.VertexCount * decl.VertexStride];
-
-            var elements = decl.GetVertexElements();
-
-            for (int i = 0; i < src.VertexCount; ++i)
-            {
-                var vrt = new VertexEncoder(dst, decl.VertexStride, i);
-
-                var jw = src.GetSkinWeights(i);
-
-                foreach (var e in elements)
-                {
-                    switch (e.VertexElementUsage)
-                    {
-                        case VertexElementUsage.Position: vrt.Encode(e, src.GetPosition(i)); break;
-                        case VertexElementUsage.Normal: vrt.Encode(e, src.GetNormal(i)); break;
-                        case VertexElementUsage.Tangent: vrt.Encode(e, src.GetTangent(i)); break;
-                        case VertexElementUsage.Color: vrt.Encode(e, src.GetColor(i, e.UsageIndex)); break;
-                        case VertexElementUsage.TextureCoordinate: vrt.Encode(e, src.GetTextureCoord(i, e.UsageIndex)); break;
-                        case VertexElementUsage.BlendIndices: vrt.Encode(e, jw.Indices); break;
-                        case VertexElementUsage.BlendWeight: vrt.Encode(e, jw.Weights); break;
-                    }
-                }
-            }
-
-            return dst;
-        }        
-    }
-    
-    /// <summary>
-    /// helps encoding a vertex byte array
-    /// TODO: if the host platform is Big Endian, we need to reverse the byte order here.
-    /// </summary>
-    readonly ref struct VertexEncoder
-    {
-        #region constructors
-        public VertexEncoder(Span<Byte> array, int vertexStride, int index)
-        {
-            _Vertex = array.Slice(index * vertexStride, vertexStride);
-        }
-
-        public VertexEncoder(Span<Byte> vertex) { _Vertex = vertex; }
-
-        #endregion
-
-        #region data
-
-        private readonly Span<Byte> _Vertex;
-
-        #endregion
-
-        #region API
-
-        public void Encode(VertexElement element, Vector2 value)
-        {
-            var dstVertex = _Vertex.Slice(element.Offset);
-
-            if (element.VertexElementFormat == VertexElementFormat.Vector2)
-            {
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref value);
-                return;
-            }
-
-            throw new ArgumentException(nameof(element));
-        }
-
-        public void Encode(VertexElement element, Vector3 value)
-        {
-            var dstVertex = _Vertex.Slice(element.Offset);
-
-            if (element.VertexElementFormat == VertexElementFormat.Vector3)
-            {
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref value);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.Color)
-            {
-                var c = new Color(value);
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref c);
-                return;
-            }
-
-            throw new ArgumentException(nameof(element));
-        }
-
-        public void Encode(VertexElement element, Vector4 value)
-        {
-            var dstVertex = _Vertex.Slice(element.Offset);
-
-            if (element.VertexElementFormat == VertexElementFormat.Vector4)
-            {
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref value);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.Byte4)
-            {
-                var c = new Byte4(value);
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref c);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.Color)
-            {
-                var c = new Color(value);
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref c);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.Short4)
-            {
-                var ns = new Short4(value);
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref ns);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.NormalizedShort4)
-            {
-                var ns = new NormalizedShort4(value);
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref ns);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.HalfVector4)
-            {
-                var ns = new HalfVector4(value);
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref ns);
-                return;
-            }
-
-            throw new ArgumentException(nameof(element));
-        }
-
-        public void Encode(VertexElement element, Short4 value)
-        {
-            var dstVertex = _Vertex.Slice(element.Offset);
-
-            if (element.VertexElementFormat == VertexElementFormat.Vector4)
-            {
-                var v4 = value.ToVector4();
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref v4);
-                return;
-            }
-
-            if (element.VertexElementFormat == VertexElementFormat.Short4)
-            {
-                System.Runtime.InteropServices.MemoryMarshal.Write(dstVertex, ref value);
-                return;
-            }
-
-            throw new ArgumentException(nameof(element));
-        }
-
-        #endregion
-    }
-}

+ 3 - 2
src/MonoScene.Runtime.Model3D/ModelGraph/AnimationTrackInfo.cs → src/MonoScene.Runtime.Content/Model/AnimationTrackInfo.cs

@@ -2,9 +2,10 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 
 
-namespace MonoScene.Graphics
+namespace MonoScene.Graphics.Content
 {
 {
-    public class AnimationTrackInfo : Content.BaseContent
+    [System.Diagnostics.DebuggerDisplay("{Name} {Duration}s")]
+    public class AnimationTrackInfo : BaseContent
     {
     {
         public AnimationTrackInfo(string name, object tag, float duration)
         public AnimationTrackInfo(string name, object tag, float duration)
             : base(name, tag)
             : base(name, tag)

+ 10 - 7
src/MonoScene.Runtime.Model3D/ModelGraph/ArmatureTemplate.cs → src/MonoScene.Runtime.Content/Model/ArmatureContent.cs

@@ -3,18 +3,21 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 
 
-namespace MonoScene.Graphics
+namespace MonoScene.Graphics.Content
 {
 {
-    public class ArmatureTemplate
+    /// <summary>
+    /// Represents a collection of hierarchically connected <see cref="NodeContent"/> elements.
+    /// </summary>
+    public class ArmatureContent
     {
     {
         #region lifecycle
         #region lifecycle
 
 
         /// <summary>
         /// <summary>
-        /// Creates an armature from an array of <see cref="NodeTemplate"/>
+        /// Creates an armature from an array of <see cref="NodeContent"/>
         /// </summary>
         /// </summary>
-        /// <param name="nodes">a flattened array of <see cref="NodeTemplate"/> objects.</param>
+        /// <param name="nodes">a flattened array of <see cref="NodeContent"/> objects.</param>
         /// <param name="atracks">animation tracks info</param>
         /// <param name="atracks">animation tracks info</param>
-        internal ArmatureTemplate(NodeTemplate[] nodes, AnimationTrackInfo[] atracks)
+        public ArmatureContent(NodeContent[] nodes, AnimationTrackInfo[] atracks)
         {
         {
             if (nodes == null) throw new ArgumentNullException(nameof(nodes));
             if (nodes == null) throw new ArgumentNullException(nameof(nodes));
 
 
@@ -43,7 +46,7 @@ namespace MonoScene.Graphics
 
 
         #region data
         #region data
 
 
-        private readonly NodeTemplate[] _NodeTemplates;
+        private readonly NodeContent[] _NodeTemplates;
         private readonly AnimationTrackInfo[] _AnimationTracks;
         private readonly AnimationTrackInfo[] _AnimationTracks;
 
 
         #endregion
         #endregion
@@ -52,7 +55,7 @@ namespace MonoScene.Graphics
 
 
         public int Count => _NodeTemplates.Length;
         public int Count => _NodeTemplates.Length;
 
 
-        public NodeTemplate this[int index] => _NodeTemplates[index];
+        public NodeContent this[int index] => _NodeTemplates[index];
 
 
         public IReadOnlyList<AnimationTrackInfo> Animations => _AnimationTracks;
         public IReadOnlyList<AnimationTrackInfo> Animations => _AnimationTracks;
 
 

+ 120 - 0
src/MonoScene.Runtime.Content/Model/NodeContent.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+
+using XNAV3 = Microsoft.Xna.Framework.Vector3;
+using XNAMAT = Microsoft.Xna.Framework.Matrix;
+using XNAQUAT = Microsoft.Xna.Framework.Quaternion;
+using SPARSE8 = Microsoft.Xna.Framework.Vector4;
+
+namespace MonoScene.Graphics.Content
+{
+    /// <summary>
+    /// Represents a hierarchical element within a <see cref="ArmatureContent"/>.
+    /// </summary>
+    [System.Diagnostics.DebuggerDisplay("[{LogicalNodeIndex}] {Name}")]
+    public class NodeContent : BaseContent
+    {
+        #region lifecycle
+
+        public NodeContent(int thisIndex, int parentIndex, int[] childIndices)
+        {
+            if (parentIndex >= thisIndex) throw new ArgumentOutOfRangeException(nameof(parentIndex));
+            if (childIndices.Any(item => item <= thisIndex)) throw new ArgumentOutOfRangeException(nameof(childIndices));
+
+            _ThisIndex = thisIndex;
+            _ParentIndex = parentIndex;
+            _ChildIndices = childIndices;
+        }
+
+        #endregion
+
+        #region data
+
+        /// <summary>
+        /// the index of this node within <see cref="ModelTemplate._NodeTemplates"/>
+        /// </summary>
+        private readonly int _ThisIndex;
+
+        /// <summary>
+        /// the index of the parent node within <see cref="ModelTemplate._NodeTemplates"/>
+        /// </summary>
+        private readonly int _ParentIndex;
+        private readonly int[] _ChildIndices;
+
+        private XNAMAT _LocalMatrix;
+
+        private bool _UseAnimatedTransforms;        
+
+        private AnimatableProperty<XNAV3> _LocalScale;
+        private AnimatableProperty<XNAQUAT> _LocalRotation;
+        private AnimatableProperty<XNAV3> _LocalTranslation;
+        // private AnimatableProperty<SPARSE8> _LocalMorphing;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// Gets the index of the source <see cref="Schema2.Node"/> in <see cref="ModelTemplate._NodeTemplates"/>
+        /// </summary>
+        public int ThisIndex => _ThisIndex;
+
+        /// <summary>
+        /// Gets the index of the parent <see cref="NodeTemplate"/> in <see cref="ModelTemplate._NodeTemplates"/>
+        /// </summary>
+        public int ParentIndex => _ParentIndex;
+
+        /// <summary>
+        /// Gets the list of indices of the children <see cref="NodeTemplate"/> in <see cref="ModelTemplate._NodeTemplates"/>
+        /// </summary>
+        public IReadOnlyList<int> ChildIndices => _ChildIndices;
+
+
+        public bool UseAnimatedTransforms => _UseAnimatedTransforms;
+        public XNAMAT LocalMatrix => _LocalMatrix;        
+        public AnimatableProperty<XNAV3> LocalScale => _LocalScale;
+        public AnimatableProperty<XNAQUAT> LocalRotation => _LocalRotation;
+        public AnimatableProperty<XNAV3> LocalTranslation => _LocalTranslation;
+
+        #endregion
+
+        #region API
+
+        public void SetLocalMatrix(XNAMAT matrix)
+        {
+            _LocalMatrix = matrix;
+            _UseAnimatedTransforms = false;
+        }
+
+        public void SetLocalTransform(AnimatableProperty<XNAV3> s, AnimatableProperty<XNAQUAT> r, AnimatableProperty<XNAV3> t)
+        {            
+            var ss = s != null && s.IsAnimated;
+            var rr = r != null && r.IsAnimated;
+            var tt = t != null && t.IsAnimated;
+
+            if (!(ss || rr || tt))
+            {
+                _UseAnimatedTransforms = false;
+                _LocalScale = null;
+                _LocalRotation = null;
+                _LocalTranslation = null;
+                return;
+            }
+
+            _UseAnimatedTransforms = true;
+            _LocalScale = s;
+            _LocalRotation = r;
+            _LocalTranslation = t;
+
+            var m = XNAMAT.Identity;
+            if (s != null) m *= XNAMAT.CreateScale(s.Value);
+            if (r != null) m *= XNAMAT.CreateFromQuaternion(r.Value);
+            if (t != null) m.Translation = t.Value;
+            _LocalMatrix = m;
+        }
+
+        #endregion
+    }
+}

+ 2 - 6
src/MonoScene.Runtime.Content/MonoScene.Runtime.Content.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
+    <TargetFramework>netstandard2.0</TargetFramework>
     <RootNamespace>Microsoft.Xna.Framework.RuntimeContent.Graphics</RootNamespace>
     <RootNamespace>Microsoft.Xna.Framework.RuntimeContent.Graphics</RootNamespace>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   </PropertyGroup>
@@ -9,10 +9,6 @@
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.1825-develop" PrivateAssets="all" />
     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.1825-develop" PrivateAssets="all" />
     <PackageReference Include="System.Memory" Version="4.5.4" />
     <PackageReference Include="System.Memory" Version="4.5.4" />
-  </ItemGroup>
-
-  <ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
-    <PackageReference Include="System.ValueTuple" Version="4.5.0" />    
-  </ItemGroup>
+  </ItemGroup>  
 
 
 </Project>
 </Project>

+ 5 - 3
src/MonoScene.Runtime.Model3D/ModelGraph/ArmatureInstance.cs

@@ -4,12 +4,14 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
+using MonoScene.Graphics.Content;
+
 using XFORM = Microsoft.Xna.Framework.Matrix;
 using XFORM = Microsoft.Xna.Framework.Matrix;
 
 
 namespace MonoScene.Graphics
 namespace MonoScene.Graphics
 {
 {
     /// <summary>
     /// <summary>
-    /// Represents a specific and independent state of a <see cref="ArmatureTemplate"/>.
+    /// Represents a specific and independent state of a <see cref="Content.ArmatureContent"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     /// An <see cref="ArmatureTemplate"/> represents the layout, graph and initial state of a skeleton, and it's a READ ONLY OBJECT.
     /// An <see cref="ArmatureTemplate"/> represents the layout, graph and initial state of a skeleton, and it's a READ ONLY OBJECT.
@@ -20,7 +22,7 @@ namespace MonoScene.Graphics
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        internal ArmatureInstance(ArmatureTemplate armature)
+        internal ArmatureInstance(ArmatureContent armature)
         {
         {
             _Template = armature;
             _Template = armature;
             _NodeInstances = new NodeInstance[armature.Count];
             _NodeInstances = new NodeInstance[armature.Count];
@@ -40,7 +42,7 @@ namespace MonoScene.Graphics
 
 
         #region data
         #region data
 
 
-        private ArmatureTemplate _Template;
+        private ArmatureContent _Template;
         private NodeInstance[] _NodeInstances;              
         private NodeInstance[] _NodeInstances;              
 
 
         #endregion
         #endregion

+ 5 - 3
src/MonoScene.Runtime.Model3D/ModelGraph/DrawableTemplate.cs

@@ -3,6 +3,8 @@ using System.Collections.Generic;
 using System.Numerics;
 using System.Numerics;
 using System.Text;
 using System.Text;
 
 
+using MonoScene.Graphics.Content;
+
 using XNAMAT = Microsoft.Xna.Framework.Matrix;
 using XNAMAT = Microsoft.Xna.Framework.Matrix;
 
 
 namespace MonoScene.Graphics
 namespace MonoScene.Graphics
@@ -42,7 +44,7 @@ namespace MonoScene.Graphics
     /// This class is the 'glue' that binds a mesh with a <see cref="NodeTemplate"/> so we
     /// This class is the 'glue' that binds a mesh with a <see cref="NodeTemplate"/> so we
     /// can calculate the local transform matrix of the mesh we want to render.
     /// can calculate the local transform matrix of the mesh we want to render.
     /// </remarks>    
     /// </remarks>    
-    abstract class DrawableTemplate : Content.BaseContent, IDrawableTemplate
+    abstract class DrawableTemplate : BaseContent, IDrawableTemplate
     {
     {
         #region lifecycle
         #region lifecycle
 
 
@@ -85,7 +87,7 @@ namespace MonoScene.Graphics
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        public RigidDrawableTemplate(int meshIndex, NodeTemplate node)
+        public RigidDrawableTemplate(int meshIndex, NodeContent node)
             : base(node.Name, meshIndex)
             : base(node.Name, meshIndex)
         {
         {
             _NodeIndex = node.ThisIndex;
             _NodeIndex = node.ThisIndex;
@@ -122,7 +124,7 @@ namespace MonoScene.Graphics
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        public SkinnedDrawableTemplate(int meshIndex, NodeTemplate morphNode, string ownerNname, (NodeTemplate, XNAMAT)[] skinNodes)
+        public SkinnedDrawableTemplate(int meshIndex, NodeContent morphNode, string ownerNname, (NodeContent, XNAMAT)[] skinNodes)
             : base(ownerNname, meshIndex)
             : base(ownerNname, meshIndex)
         {
         {
             // _MorphNodeIndex = indexFunc(morphNode);
             // _MorphNodeIndex = indexFunc(morphNode);

+ 6 - 3
src/MonoScene.Runtime.Model3D/ModelGraph/ModelCollection.cs

@@ -2,6 +2,8 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 
 
+using MonoScene.Graphics.Content;
+
 using MODELMESH = MonoScene.Graphics.Mesh;
 using MODELMESH = MonoScene.Graphics.Mesh;
 
 
 
 
@@ -15,7 +17,8 @@ namespace MonoScene.Graphics
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        public DeviceModelCollection(MeshCollection meshes, ArmatureTemplate[] armatures, ModelTemplate[] models, int defaultModelIndex) :base(meshes, armatures, models,defaultModelIndex)
+        public DeviceModelCollection(MeshCollection meshes, ArmatureContent[] armatures, ModelTemplate[] models, int defaultModelIndex)
+            : base(meshes, armatures, models,defaultModelIndex)
         {
         {
             SharedMeshes = meshes;
             SharedMeshes = meshes;
         }
         }
@@ -45,7 +48,7 @@ namespace MonoScene.Graphics
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        public ModelCollection(IMeshCollection meshes, ArmatureTemplate[] armatures, ModelTemplate[] models, int defaultModelIndex)
+        public ModelCollection(IMeshCollection meshes, ArmatureContent[] armatures, ModelTemplate[] models, int defaultModelIndex)
         {
         {
             _SharedArmatures = armatures;
             _SharedArmatures = armatures;
             _DefaultModelIndex = defaultModelIndex;
             _DefaultModelIndex = defaultModelIndex;
@@ -67,7 +70,7 @@ namespace MonoScene.Graphics
         /// <summary>
         /// <summary>
         /// Multiple <see cref="ModelTemplate"/> at <see cref="_Models"/> might share the same <see cref="ArmatureTemplate"/>.
         /// Multiple <see cref="ModelTemplate"/> at <see cref="_Models"/> might share the same <see cref="ArmatureTemplate"/>.
         /// </summary>
         /// </summary>
-        private ArmatureTemplate[] _SharedArmatures;
+        private ArmatureContent[] _SharedArmatures;
 
 
         /// <summary>
         /// <summary>
         /// Models available in this collection.
         /// Models available in this collection.

+ 9 - 8
src/MonoScene.Runtime.Model3D/ModelGraph/ModelTemplate.cs

@@ -7,17 +7,19 @@ using System.Threading.Tasks;
 
 
 using Microsoft.Xna.Framework.Graphics;
 using Microsoft.Xna.Framework.Graphics;
 
 
+using MonoScene.Graphics.Content;
+
 namespace MonoScene.Graphics
 namespace MonoScene.Graphics
 {
 {
     /// <summary>
     /// <summary>
     /// Defines a templatized representation of a <see cref="Schema2.Scene"/> that can be used
     /// Defines a templatized representation of a <see cref="Schema2.Scene"/> that can be used
     /// to create <see cref="ModelInstance"/>, which can help render a scene on a client application.
     /// to create <see cref="ModelInstance"/>, which can help render a scene on a client application.
     /// </summary>
     /// </summary>
-    public class ModelTemplate : Content.BaseContent
+    public class ModelTemplate : BaseContent
     {
     {
         #region lifecycle        
         #region lifecycle        
 
 
-        public ModelTemplate(string modelName, ArmatureTemplate armature, IDrawableTemplate[] drawables)
+        public ModelTemplate(string modelName, ArmatureContent armature, IDrawableTemplate[] drawables)
             : base(modelName)
             : base(modelName)
         {            
         {            
             _Armature = armature;
             _Armature = armature;
@@ -28,13 +30,12 @@ namespace MonoScene.Graphics
 
 
         #region data        
         #region data        
 
 
-        internal readonly ArmatureTemplate _Armature;
-        
-        private IMeshCollection _Meshes;        
+        internal readonly ArmatureContent _Armature;
 
 
         // this is the collection of "what needs to be rendered", and it binds meshes with armatures
         // this is the collection of "what needs to be rendered", and it binds meshes with armatures
         internal readonly IDrawableTemplate[] _DrawableReferences;
         internal readonly IDrawableTemplate[] _DrawableReferences;
 
 
+        private IMeshCollection _SharedMeshes;
         private Effect[] _SharedEffects;
         private Effect[] _SharedEffects;
 
 
         #endregion
         #endregion
@@ -45,10 +46,10 @@ namespace MonoScene.Graphics
 
 
         public IMeshCollection Meshes
         public IMeshCollection Meshes
         {
         {
-            get => _Meshes;
+            get => _SharedMeshes;
             set
             set
             {
             {
-                _Meshes = value;
+                _SharedMeshes = value;
                 _SharedEffects = null;
                 _SharedEffects = null;
             }
             }
         }
         }
@@ -60,7 +61,7 @@ namespace MonoScene.Graphics
                 if (_SharedEffects != null) return _SharedEffects;
                 if (_SharedEffects != null) return _SharedEffects;
 
 
                 var meshIndices = _DrawableReferences.Select(item => item.MeshIndex);
                 var meshIndices = _DrawableReferences.Select(item => item.MeshIndex);
-                _SharedEffects = _Meshes.GetSharedEffects(meshIndices);
+                _SharedEffects = _SharedMeshes.GetSharedEffects(meshIndices);
 
 
                 return _SharedEffects;
                 return _SharedEffects;
             }
             }

+ 84 - 0
src/MonoScene.Runtime.Model3D/ModelGraph/NodeContent.Evaluator.cs

@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using XNAV3 = Microsoft.Xna.Framework.Vector3;
+using XNAMAT = Microsoft.Xna.Framework.Matrix;
+using XNAQUAT = Microsoft.Xna.Framework.Quaternion;
+using SPARSE8 = Microsoft.Xna.Framework.Vector4;
+
+namespace MonoScene.Graphics.Content
+{
+    static class NodeTemplateEvaluator
+    {
+        public static AffineTransform GetLocalTransform(this NodeContent node)
+        {
+            var s = node.LocalScale?.Value;
+            var r = node.LocalRotation?.Value;
+            var t = node.LocalTranslation?.Value;
+
+            return new AffineTransform(s, r, t);
+        }
+
+        public static AffineTransform GetLocalTransform(this NodeContent node, int trackIndex, float time)
+        {
+            if (!node.UseAnimatedTransforms || trackIndex < 0) return node.GetLocalTransform();
+
+            var s = node.LocalScale?.GetValueAt(trackIndex, time);
+            var r = node.LocalRotation?.GetValueAt(trackIndex, time);
+            var t = node.LocalTranslation?.GetValueAt(trackIndex, time);
+
+            return new AffineTransform(s, r, t);
+        }
+
+        public static AffineTransform GetLocalTransform(this NodeContent node, ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            if (!node.UseAnimatedTransforms) return node.GetLocalTransform();
+
+            Span<AffineTransform> xforms = stackalloc AffineTransform[track.Length];
+
+            for (int i = 0; i < xforms.Length; ++i)
+            {
+                xforms[i] = node.GetLocalTransform(track[i], time[i]);
+            }
+
+            return AffineTransform.Blend(xforms, weight);
+        }
+
+        public static XNAMAT GetLocalMatrix(this NodeContent node, int trackIndex, float time)
+        {
+            if (!node.UseAnimatedTransforms || trackIndex < 0) return node.LocalMatrix;
+
+            return node.GetLocalTransform(trackIndex, time).Matrix;
+        }
+
+        public static XNAMAT GetLocalMatrix(this NodeContent node, ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            if (!node.UseAnimatedTransforms) return node.LocalMatrix;
+
+            return node.GetLocalTransform(track, time, weight).Matrix;
+        }
+
+        /*
+        public static SPARSE8 GetMorphWeights(this NodeContent node,int trackLogicalIndex, float time)
+        {
+            if (trackLogicalIndex < 0) return _Morphing.Value;
+
+            return _Morphing.GetValueAt(trackLogicalIndex, time);
+        }
+        
+        public static SPARSE8 GetMorphWeights(this NodeContent node,ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            if (!_Morphing.IsAnimated) return _Morphing.Value;
+
+            Span<SPARSE8> xforms = stackalloc SPARSE8[track.Length];
+
+            for (int i = 0; i < xforms.Length; ++i)
+            {
+                xforms[i] = GetMorphWeights(track[i], time[i]);
+            }
+
+            return SPARSE8.Blend(xforms, weight);
+        }*/
+    }
+}

+ 8 - 3
src/MonoScene.Runtime.Model3D/ModelGraph/NodeInstance.cs

@@ -2,20 +2,22 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 
 
+using MonoScene.Graphics.Content;
+
 using XFORM = Microsoft.Xna.Framework.Matrix;
 using XFORM = Microsoft.Xna.Framework.Matrix;
 // using SPARSE8 = Microsoft.Xna.Framework.Vector4;
 // using SPARSE8 = Microsoft.Xna.Framework.Vector4;
 
 
 namespace MonoScene.Graphics
 namespace MonoScene.Graphics
 {
 {
     /// <summary>
     /// <summary>
-    /// Defines a node of a scene graph in <see cref="ModelInstance"/>
+    /// Represents a hierarchical element within an <see cref="ArmatureInstance"/>, mirroring a <see cref="NodeContent"/>.
     /// </summary>
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("{Name}")]
     [System.Diagnostics.DebuggerDisplay("{Name}")]
     public sealed class NodeInstance
     public sealed class NodeInstance
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        internal NodeInstance(NodeTemplate template, NodeInstance parent)
+        internal NodeInstance(NodeContent template, NodeInstance parent)
         {
         {
             _Template = template;
             _Template = template;
             _Parent = parent;
             _Parent = parent;
@@ -25,7 +27,7 @@ namespace MonoScene.Graphics
 
 
         #region data
         #region data
 
 
-        private readonly NodeTemplate _Template;
+        private readonly NodeContent _Template;
         private readonly NodeInstance _Parent;
         private readonly NodeInstance _Parent;
 
 
         private XFORM _LocalMatrix;
         private XFORM _LocalMatrix;
@@ -73,6 +75,9 @@ namespace MonoScene.Graphics
         /// <summary>
         /// <summary>
         /// Gets a value indicating whether any of the transforms down the node tree graph has been modified.
         /// Gets a value indicating whether any of the transforms down the node tree graph has been modified.
         /// </summary>
         /// </summary>
+        /// <remarks>
+        /// When this is true, we need to recalculate our <see cref="ModelMatrix"/>.
+        /// </remarks>
         private bool _TransformChainIsDirty
         private bool _TransformChainIsDirty
         {
         {
             get
             get

+ 0 - 175
src/MonoScene.Runtime.Model3D/ModelGraph/NodeTemplate.cs

@@ -1,175 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Linq;
-
-using XNAV3 = Microsoft.Xna.Framework.Vector3;
-using XNAV4 = Microsoft.Xna.Framework.Vector4;
-using XNAQUAT = Microsoft.Xna.Framework.Quaternion;
-using XNAMAT = Microsoft.Xna.Framework.Matrix;
-using SPARSE8 = Microsoft.Xna.Framework.Vector4;
-
-namespace MonoScene.Graphics
-{
-    /// <summary>
-    /// Defines a hierarchical transform node of a scene graph tree.
-    /// </summary>
-    [System.Diagnostics.DebuggerDisplay("[{LogicalNodeIndex}] {Name}")]
-    public class NodeTemplate : Content.BaseContent
-    {
-        #region lifecycle
-
-        internal NodeTemplate(int thisIndex, int parentIndex, int[] childIndices)
-        {
-            if (parentIndex >= thisIndex) throw new ArgumentOutOfRangeException(nameof(parentIndex));
-            if (childIndices.Any(item => item <= thisIndex)) throw new ArgumentOutOfRangeException(nameof(childIndices));
-
-            _ThisIndex = thisIndex;
-            _ParentIndex = parentIndex;
-            _ChildIndices = childIndices;
-        }
-
-        #endregion
-
-        #region data
-
-        /// <summary>
-        /// the index of this node within <see cref="ModelTemplate._NodeTemplates"/>
-        /// </summary>
-        private readonly int _ThisIndex;
-
-        /// <summary>
-        /// the index of the parent node within <see cref="ModelTemplate._NodeTemplates"/>
-        /// </summary>
-        private readonly int _ParentIndex;
-        private readonly int[] _ChildIndices;
-
-        private XNAMAT _LocalMatrix;        
-
-        private bool _UseAnimatedTransforms;
-
-        private AffineTransform _LocalTransform;
-        private AnimatableProperty<XNAV3> _Scale;
-        private AnimatableProperty<XNAQUAT> _Rotation;
-        private AnimatableProperty<XNAV3> _Translation;
-
-        // private AnimatableProperty<SPARSE8> _Morphing;
-
-        #endregion
-
-        #region properties
-
-        /// <summary>
-        /// Gets the index of the source <see cref="Schema2.Node"/> in <see cref="ModelTemplate._NodeTemplates"/>
-        /// </summary>
-        public int ThisIndex => _ThisIndex;
-
-        /// <summary>
-        /// Gets the index of the parent <see cref="NodeTemplate"/> in <see cref="ModelTemplate._NodeTemplates"/>
-        /// </summary>
-        public int ParentIndex => _ParentIndex;
-
-        /// <summary>
-        /// Gets the list of indices of the children <see cref="NodeTemplate"/> in <see cref="ModelTemplate._NodeTemplates"/>
-        /// </summary>
-        public IReadOnlyList<int> ChildIndices => _ChildIndices;
-
-        public XNAMAT LocalMatrix => _LocalMatrix;        
-
-        #endregion
-
-        #region API
-
-        public void SetLocalMatrix(XNAMAT matrix)
-        {
-            _LocalMatrix = matrix;
-            _UseAnimatedTransforms = false;
-        }
-
-        public void SetLocalTransform(AnimatableProperty<XNAV3> s, AnimatableProperty<XNAQUAT> r, AnimatableProperty<XNAV3> t)
-        {            
-            var ss = s != null && s.IsAnimated;
-            var rr = r != null && r.IsAnimated;
-            var tt = t != null && t.IsAnimated;
-
-            if (!(ss || rr || tt))
-            {
-                _UseAnimatedTransforms = false;
-                _Scale = null;
-                _Rotation = null;
-                _Translation = null;
-                return;
-            }
-
-            _UseAnimatedTransforms = true;
-            _Scale = s;
-            _Rotation = r;
-            _Translation = t;
-
-            _LocalMatrix = AffineTransform.CreateFromAny(null, s.Value, r.Value, t.Value).Matrix;
-        }
-
-        /*
-        public SPARSE8 GetMorphWeights(int trackLogicalIndex, float time)
-        {
-            if (trackLogicalIndex < 0) return _Morphing.Value;
-
-            return _Morphing.GetValueAt(trackLogicalIndex, time);
-        }
-        
-        public SPARSE8 GetMorphWeights(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
-        {
-            if (!_Morphing.IsAnimated) return _Morphing.Value;
-
-            Span<SPARSE8> xforms = stackalloc SPARSE8[track.Length];
-
-            for (int i = 0; i < xforms.Length; ++i)
-            {
-                xforms[i] = GetMorphWeights(track[i], time[i]);
-            }
-
-            return SPARSE8.Blend(xforms, weight);
-        }*/
-
-        public AffineTransform GetLocalTransform(int trackIndex, float time)
-        {
-            if (!_UseAnimatedTransforms || trackIndex < 0) return _LocalTransform;
-
-            var s = _Scale?.GetValueAt(trackIndex, time);
-            var r = _Rotation?.GetValueAt(trackIndex, time);
-            var t = _Translation?.GetValueAt(trackIndex, time);
-
-            return new AffineTransform(s, r, t);
-        }
-
-        public AffineTransform GetLocalTransform(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
-        {
-            if (!_UseAnimatedTransforms) return _LocalTransform;
-
-            Span<AffineTransform> xforms = stackalloc AffineTransform[track.Length];
-
-            for (int i = 0; i < xforms.Length; ++i)
-            {
-                xforms[i] = GetLocalTransform(track[i], time[i]);
-            }
-
-            return AffineTransform.Blend(xforms, weight);
-        }
-
-        public XNAMAT GetLocalMatrix(int trackIndex, float time)
-        {
-            if (!_UseAnimatedTransforms || trackIndex < 0) return _LocalMatrix;
-
-            return GetLocalTransform(trackIndex, time).Matrix;
-        }
-
-        public XNAMAT GetLocalMatrix(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
-        {
-            if (!_UseAnimatedTransforms) return _LocalMatrix;
-
-            return GetLocalTransform(track, time, weight).Matrix;
-        }
-
-        #endregion
-    }
-}