Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
File last commit:
Show/Diff file:
Action:
FNA/src/Graphics/Model.cs
236 lines | 6.0 KiB | text/x-csharp | CSharpLexer
#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
* Copyright 2009-2020 Ethan Lee and the MonoGame Team
*
* Released under the Microsoft Public License.
* See LICENSE for details.
*/
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
#endregion
namespace Microsoft.Xna.Framework.Graphics
{
/// <summary>
/// A basic 3D model with per mesh parent bones.
/// </summary>
public class Model
{
#region Public Properties
/// <summary>
/// A collection of <see cref="ModelBone"/> objects which describe how each mesh in the
/// mesh collection for this model relates to its parent mesh.
/// </summary>
public ModelBoneCollection Bones
{
get;
private set;
}
/// <summary>
/// A collection of <see cref="ModelMesh"/> objects which compose the model. Each <see cref="ModelMesh"/>
/// in a model may be moved independently and may be composed of multiple materials
/// identified as <see cref="ModelMeshPart"/> objects.
/// </summary>
public ModelMeshCollection Meshes
{
get;
private set;
}
/// <summary>
/// Root bone for this model.
/// </summary>
public ModelBone Root
{
get;
internal set;
}
/// <summary>
/// Custom attached object.
/// <remarks>
/// Skinning data is example of attached object for model.
/// </remarks>
/// </summary>
public object Tag
{
get;
set;
}
#endregion
#region Private Static Variables
private static Matrix[] sharedDrawBoneMatrices;
#endregion
#region Internal Constructor
/// <summary>
/// Constructs a model.
/// </summary>
/// <param name="graphicsDevice">A valid reference to <see cref="GraphicsDevice"/>.</param>
/// <param name="bones">The collection of bones.</param>
/// <param name="meshes">The collection of meshes.</param>
internal Model(GraphicsDevice graphicsDevice, List<ModelBone> bones, List<ModelMesh> meshes)
{
Bones = new ModelBoneCollection(bones);
Meshes = new ModelMeshCollection(meshes);
}
#endregion
#region Public Methods
/// <summary>
/// Draws the model meshes.
/// </summary>
/// <param name="world">The world transform.</param>
/// <param name="view">The view transform.</param>
/// <param name="projection">The projection transform.</param>
public void Draw(Matrix world, Matrix view, Matrix projection)
{
int boneCount = Bones.Count;
if (sharedDrawBoneMatrices == null ||
sharedDrawBoneMatrices.Length < boneCount)
{
sharedDrawBoneMatrices = new Matrix[boneCount];
}
// Look up combined bone matrices for the entire model.
CopyAbsoluteBoneTransformsTo(sharedDrawBoneMatrices);
// Draw the model.
foreach (ModelMesh mesh in Meshes)
{
foreach (Effect effect in mesh.Effects)
{
IEffectMatrices effectMatricies = effect as IEffectMatrices;
if (effectMatricies == null)
{
throw new InvalidOperationException();
}
effectMatricies.World = sharedDrawBoneMatrices[mesh.ParentBone.Index] * world;
effectMatricies.View = view;
effectMatricies.Projection = projection;
}
mesh.Draw();
}
}
/// <summary>
/// Copies bone transforms relative to all parent bones of the each bone from this model to a given array.
/// </summary>
/// <param name="destinationBoneTransforms">The array receiving the transformed bones.</param>
public void CopyAbsoluteBoneTransformsTo(Matrix[] destinationBoneTransforms)
{
if (destinationBoneTransforms == null)
{
throw new ArgumentNullException("destinationBoneTransforms");
}
if (destinationBoneTransforms.Length < Bones.Count)
{
throw new ArgumentOutOfRangeException("destinationBoneTransforms");
}
int count = Bones.Count;
for (int index1 = 0; index1 < count; index1 += 1)
{
ModelBone modelBone = Bones[index1];
if (modelBone.Parent == null)
{
destinationBoneTransforms[index1] = modelBone.Transform;
}
else
{
int index2 = modelBone.Parent.Index;
Matrix modelBoneTransform = modelBone.Transform;
Matrix.Multiply(
ref modelBoneTransform,
ref destinationBoneTransforms[index2],
out destinationBoneTransforms[index1]
);
}
}
}
/// <summary>
/// Copies bone transforms relative to <see cref="Model.Root"/> bone from a given array to this model.
/// </summary>
/// <param name="sourceBoneTransforms">The array of prepared bone transform data.</param>
public void CopyBoneTransformsFrom(Matrix[] sourceBoneTransforms)
{
if (sourceBoneTransforms == null)
{
throw new ArgumentNullException("sourceBoneTransforms");
}
if (sourceBoneTransforms.Length < Bones.Count)
{
throw new ArgumentOutOfRangeException("sourceBoneTransforms");
}
for (int i = 0; i < sourceBoneTransforms.Length; i += 1)
{
Bones[i].Transform = sourceBoneTransforms[i];
}
}
/// <summary>
/// Copies bone transforms relative to <see cref="Model.Root"/> bone from this model to a given array.
/// </summary>
/// <param name="destinationBoneTransforms">The array receiving the transformed bones.</param>
public void CopyBoneTransformsTo(Matrix[] destinationBoneTransforms)
{
if (destinationBoneTransforms == null)
{
throw new ArgumentNullException("destinationBoneTransforms");
}
if (destinationBoneTransforms.Length < Bones.Count)
{
throw new ArgumentOutOfRangeException("destinationBoneTransforms");
}
for (int i = 0; i < destinationBoneTransforms.Length; i += 1)
{
destinationBoneTransforms[i] = Bones[i].Transform;
}
}
#endregion
#region Internal Methods
internal void BuildHierarchy()
{
Matrix globalScale = Matrix.CreateScale(0.01f);
foreach (ModelBone node in Root.Children)
{
BuildHierarchy(node, Root.Transform * globalScale, 0);
}
}
#endregion
#region Private Methods
private void BuildHierarchy(ModelBone node, Matrix parentTransform, int level)
{
node.ModelTransform = node.Transform * parentTransform;
foreach (ModelBone child in node.Children)
{
BuildHierarchy(child, node.ModelTransform, level + 1);
}
}
#endregion
}
}