PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 7ms RepoModel.GetById 33ms app.codeStats 0ms

/ContentSystem/Rendering/MeshAnimationData.cs

#
C# | 206 lines | 109 code | 16 blank | 81 comment | 11 complexity | e803a852f432ba8acda0b7440a919f28 MD5 | raw file
  1using System;
  2using System.IO;
  3using Delta.Utilities;
  4using Delta.Utilities.Datatypes;
  5using Delta.Utilities.Helpers;
  6
  7namespace Delta.ContentSystem.Rendering
  8{
  9	/// <summary>
 10	/// Mesh Animation data class, which keeps all the data (matrices) for one
 11	/// mesh animation. This can be something like a simple Idle animation or
 12	/// some really complex cinematic animation for a character with bones.
 13	/// See BoneData for the bone details. Mesh and MeshAnimations must fit.
 14	/// </summary>
 15	public class MeshAnimationData : Content, ISaveLoadBinary
 16	{
 17		#region Constants
 18		/// <summary>
 19		/// Version number for this MeshData. If this goes above 1, we need
 20		/// to support loading older versions as well. Saving is always going
 21		/// to be the latest version (this one).
 22		/// </summary>
 23		private const int CurrentVersion = 1;
 24		#endregion
 25
 26		#region Get (Static)
 27		/// <summary>
 28		/// Get and load content based on the content name. This method makes sure
 29		/// we do not load the same content twice (the constructor is protected).
 30		/// </summary>
 31		/// <param name="contentName">Content name we want to load, this is
 32		/// passed onto the Content System, which will do the actual loading with
 33		/// help of the Load method in this class.</param>
 34		/// <returns>The loaded Content object, always unique for the same
 35		/// name, this helps comparing data.</returns>
 36		public static MeshAnimationData Get(string contentName)
 37		{
 38			return Get<MeshAnimationData>(contentName,
 39				ContentType.MeshAnimation);
 40		}
 41		#endregion
 42
 43		#region Frames (Public)
 44		/// <summary>
 45		/// Array of animation frames (as array of bone matrices), e.g.
 46		/// <para />
 47		/// Frames[0] -> Frame 1
 48		///   Frames[0][0] -> Bone Matrix 1
 49		///   Frames[0][1] -> Bone Matrix 2
 50		/// Frames[1] -> Frame 2
 51		///   Frames[1][0] -> Bone Matrix 1
 52		///   Frames[1][1] -> Bone Matrix 2
 53		/// </summary>
 54		public Matrix[][] Frames
 55		{
 56			get;
 57			private set;
 58		}
 59		#endregion
 60
 61		#region Constructors
 62		/// <summary>
 63		/// Create mesh animation data with a given set of matrices for the bones.
 64		/// </summary>
 65		/// <param name="setAnimationFrames">Set animation frames</param>
 66		public MeshAnimationData(Matrix[][] setAnimationFrames)
 67			: base(EmptyName, ContentType.MeshAnimation)
 68		{
 69			Frames = setAnimationFrames;
 70		}
 71
 72		/// <summary>
 73		/// Create mesh animation data by loading it from content, use the static
 74		/// Get method to call this.
 75		/// </summary>
 76		/// <param name="contentName">Name of the content.</param>
 77		protected MeshAnimationData(string contentName)
 78			: base(contentName, ContentType.MeshAnimation)
 79		{
 80		}
 81		#endregion
 82
 83		#region ISaveLoadBinary Members
 84		/// <summary>
 85		/// Load animation data, which is mostly animation matrices.
 86		/// </summary>
 87		/// <param name="reader">Reader</param>
 88		public void Load(BinaryReader reader)
 89		{
 90			// We currently only support our version, if more versions are added,
 91			// we need to do different loading code depending on the version here.
 92			int version = reader.ReadInt32();
 93			if (version != CurrentVersion)
 94			{
 95				Log.InvalidVersionWarning(GetType().Name, version, CurrentVersion);
 96				return;
 97			}
 98
 99			// Load the frames now
100			// At first we need the number of frames we will get
101			int frameCount = reader.ReadInt32();
102			// and at second the number of bone transformations we will get for every
103			// single frame
104			// Note:
105			// 1. The value is only be saved if we have any frames
106			// 2. We only get one number for all bones, because for every frame the
107			//		number of bones is the same
108			int boneCountPerFrame = (frameCount > 0)
109			                        	? reader.ReadInt32()
110			                        	: 0;
111
112			// Finally just reconstruct the frames now
113			Frames = new Matrix[frameCount][];
114			for (int frameId = 0; frameId < frameCount; frameId++)
115			{
116				Frames[frameId] = new Matrix[boneCountPerFrame];
117				for (int boneIndex = 0; boneIndex < boneCountPerFrame; boneIndex++)
118				{
119					Frames[frameId][boneIndex].Load(reader);
120				}
121			}
122		}
123
124		/// <summary>
125		/// Save animation data, which is mostly animation matrices.
126		/// </summary>
127		/// <param name="dataWriter">Data writer</param>
128		public void Save(BinaryWriter dataWriter)
129		{
130			dataWriter.Write(CurrentVersion);
131
132			// Save out the frames
133			// at first the number of frames in total
134			dataWriter.Write(Frames.Length);
135			// and then the number of bones / bone transformations (only if needed)
136			// Note:
137			// We can do this only once, because here we have always the same amount
138			// of bones for ALL frames, else we have to save the number of bones for
139			// every single frame
140			int boneCountPerFrame = (Frames.Length > 0)
141			                        	? Frames[0].Length
142			                        	: 0;
143			if (boneCountPerFrame > 0)
144			{
145				dataWriter.Write(boneCountPerFrame);
146			}
147
148			// Finally iterate through every frame
149			for (int frameId = 0; frameId < Frames.Length; frameId++)
150			{
151				// and every bone transformation which is in the current frame
152				for (int boneIndex = 0; boneIndex < boneCountPerFrame; boneIndex++)
153				{
154					// and save it out
155					Frames[frameId][boneIndex].Save(dataWriter);
156				}
157			}
158		}
159		#endregion
160
161		#region Methods (Private)
162
163		#region Load
164		/// <summary>
165		/// Native load method, will just load the data.
166		/// </summary>
167		/// <param name="alreadyLoadedNativeData">
168		/// The first instance that has already loaded the required content data
169		/// of this content class or just 'null' if there is none loaded yet (or
170		/// anymore).
171		/// </param>
172		protected override void Load(Content alreadyLoadedNativeData)
173		{
174			try
175			{
176				if (alreadyLoadedNativeData != null)
177				{
178					// Just clone all data
179					MeshAnimationData otherData =
180						alreadyLoadedNativeData as MeshAnimationData;
181					Frames = otherData.Frames;
182					// This object cannot be used for cloning now, but the caller (Mesh)
183					// can set itself as the NativeClassObject and allow native cloning.
184					return;
185				}
186
187				if (String.IsNullOrEmpty(RelativeFilePath) == false)
188				{
189					// Load via the ISaveLoadBinary interface methods below.
190					// Cloning should not really happen for shaders anyway.
191					FileHelper.Load(RelativeFilePath, this);
192				}
193			}
194			catch (Exception ex)
195			{
196				Log.Warning("Failed to load mesh animation data from file '" +
197				            RelativeFilePath + "': " + ex);
198				FailedToLoad = true;
199			}
200		}
201		#endregion
202
203		#endregion
204	}
205}
206