/MonoGame.Framework.Content.Pipeline/Graphics/VertexChannelCollection.cs

https://bitbucket.org/refuzion/monogame · C# · 373 lines · 197 code · 29 blank · 147 comment · 24 complexity · 18872b5dfb5c64af0aac2ee678eeb882 MD5 · raw file

  1. // MonoGame - Copyright (C) The MonoGame Team
  2. // This file is subject to the terms and conditions defined in
  3. // file 'LICENSE.txt', which is part of this source code package.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Collections;
  9. namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
  10. {
  11. /// <summary>
  12. /// Provides methods and properties for managing a list of vertex data channels.
  13. /// </summary>
  14. public sealed class VertexChannelCollection : IList<VertexChannel>, ICollection<VertexChannel>, IEnumerable<VertexChannel>, IEnumerable
  15. {
  16. List<VertexChannel> channels;
  17. VertexContent vertexContent;
  18. /// <summary>
  19. /// Gets the number of vertex channels in the collection.
  20. /// </summary>
  21. public int Count
  22. {
  23. get
  24. {
  25. return channels.Count;
  26. }
  27. }
  28. /// <summary>
  29. /// Gets or sets the vertex channel at the specified index position.
  30. /// </summary>
  31. public VertexChannel this[int index]
  32. {
  33. get
  34. {
  35. return channels[index];
  36. }
  37. set
  38. {
  39. channels[index] = value;
  40. }
  41. }
  42. /// <summary>
  43. /// Gets or sets the vertex channel with the specified name.
  44. /// </summary>
  45. public VertexChannel this[string name]
  46. {
  47. get
  48. {
  49. int index = IndexOf(name);
  50. if (index < 0)
  51. throw new ArgumentException("name");
  52. return channels[index];
  53. }
  54. set
  55. {
  56. int index = IndexOf(name);
  57. if (index < 0)
  58. throw new ArgumentException("name");
  59. channels[index] = value;
  60. }
  61. }
  62. /// <summary>
  63. /// Determines whether the collection is read-only.
  64. /// </summary>
  65. bool ICollection<VertexChannel>.IsReadOnly
  66. {
  67. get
  68. {
  69. return false;
  70. }
  71. }
  72. /// <summary>
  73. /// Creates an instance of VertexChannelCollection.
  74. /// </summary>
  75. /// <param name="vertexContent">The VertexContent object that owns this collection.</param>
  76. internal VertexChannelCollection(VertexContent vertexContent)
  77. {
  78. this.vertexContent = vertexContent;
  79. channels = new List<VertexChannel>();
  80. }
  81. /// <summary>
  82. /// Adds a new vertex channel to the end of the collection.
  83. /// </summary>
  84. /// <typeparam name="ElementType">Type of the channel.</typeparam>
  85. /// <param name="name">Name of the new channel.</param>
  86. /// <param name="channelData">Initial data for the new channel. If null, the channel is filled with the default value for that type.</param>
  87. /// <returns>The newly added vertex channel.</returns>
  88. public VertexChannel<ElementType> Add<ElementType>(string name, IEnumerable<ElementType> channelData)
  89. {
  90. return Insert(channels.Count, name, channelData);
  91. }
  92. /// <summary>
  93. /// Adds a new vertex channel to the end of the collection.
  94. /// </summary>
  95. /// <param name="name">Name of the new channel.</param>
  96. /// <param name="elementType">Type of data to be contained in the new channel.</param>
  97. /// <param name="channelData">Initial data for the new channel. If null, the channel is filled with the default value for that type.</param>
  98. /// <returns>The newly added vertex channel.</returns>
  99. public VertexChannel Add(string name, Type elementType, IEnumerable channelData)
  100. {
  101. return Insert(channels.Count, name, elementType, channelData);
  102. }
  103. /// <summary>
  104. /// Removes all vertex channels from the collection.
  105. /// </summary>
  106. public void Clear()
  107. {
  108. channels.Clear();
  109. }
  110. /// <summary>
  111. /// Determines whether the collection contains the specified vertex channel.
  112. /// </summary>
  113. /// <param name="name">Name of the channel being searched for.</param>
  114. /// <returns>true if the channel was found; false otherwise.</returns>
  115. public bool Contains(string name)
  116. {
  117. return channels.Exists(c => { return c.Name == name; });
  118. }
  119. /// <summary>
  120. /// Determines whether the collection contains the specified vertex channel.
  121. /// </summary>
  122. /// <param name="item">The channel being searched for.</param>
  123. /// <returns>true if the channel was found; false otherwise.</returns>
  124. public bool Contains(VertexChannel item)
  125. {
  126. return channels.Contains(item);
  127. }
  128. /// <summary>
  129. /// Converts the channel, at the specified index, to another vector format.
  130. /// </summary>
  131. /// <typeparam name="TargetType">Type of the target format. Can be one of the following: Single, Vector2, Vector3, Vector4, IPackedVector</typeparam>
  132. /// <param name="index">Index of the channel to be converted.</param>
  133. /// <returns>New channel in the specified format.</returns>
  134. public VertexChannel<TargetType> ConvertChannelContent<TargetType>(int index)
  135. {
  136. if (index < 0 || index >= channels.Count)
  137. throw new ArgumentOutOfRangeException("index");
  138. // Get the channel at that index
  139. VertexChannel channel = this[index];
  140. // Remove it because we cannot add a new channel with the same name
  141. RemoveAt(index);
  142. VertexChannel<TargetType> result = null;
  143. try
  144. {
  145. // Insert a new converted channel at the same index
  146. result = Insert(index, channel.Name, channel.ReadConvertedContent<TargetType>());
  147. }
  148. catch
  149. {
  150. // If anything went wrong, put the old channel back...
  151. channels.Insert(index, channel);
  152. // ...before throwing the exception again
  153. throw;
  154. }
  155. // Return the new converted channel
  156. return result;
  157. }
  158. /// <summary>
  159. /// Converts the channel, specified by name to another vector format.
  160. /// </summary>
  161. /// <typeparam name="TargetType">Type of the target format. Can be one of the following: Single, Vector2, Vector3, Vector4, IPackedVector</typeparam>
  162. /// <param name="name">Name of the channel to be converted.</param>
  163. /// <returns>New channel in the specified format.</returns>
  164. public VertexChannel<TargetType> ConvertChannelContent<TargetType>(string name)
  165. {
  166. int index = IndexOf(name);
  167. if (index < 0)
  168. throw new ArgumentException("name");
  169. return ConvertChannelContent<TargetType>(index);
  170. }
  171. /// <summary>
  172. /// Gets the vertex channel with the specified index and content type.
  173. /// </summary>
  174. /// <typeparam name="T">Type of a vertex channel.</typeparam>
  175. /// <param name="index">Index of a vertex channel.</param>
  176. /// <returns>The vertex channel.</returns>
  177. public VertexChannel<T> Get<T>(int index)
  178. {
  179. if (index < 0 || index >= channels.Count)
  180. throw new ArgumentOutOfRangeException("index");
  181. VertexChannel channel = this[index];
  182. // Make sure the channel type is as expected
  183. if (channel.ElementType != typeof(T))
  184. throw new InvalidOperationException("Mismatched channel type");
  185. return (VertexChannel<T>)channel;
  186. }
  187. /// <summary>
  188. /// Gets the vertex channel with the specified name and content type.
  189. /// </summary>
  190. /// <typeparam name="T">Type of the vertex channel.</typeparam>
  191. /// <param name="name">Name of a vertex channel.</param>
  192. /// <returns>The vertex channel.</returns>
  193. public VertexChannel<T> Get<T>(string name)
  194. {
  195. int index = IndexOf(name);
  196. if (index < 0)
  197. throw new ArgumentException("name");
  198. return Get<T>(index);
  199. }
  200. /// <summary>
  201. /// Gets an enumerator that iterates through the vertex channels of a collection.
  202. /// </summary>
  203. /// <returns>Enumerator for the collection.</returns>
  204. public IEnumerator<VertexChannel> GetEnumerator()
  205. {
  206. return channels.GetEnumerator();
  207. }
  208. /// <summary>
  209. /// Determines the index of a vertex channel with the specified name.
  210. /// </summary>
  211. /// <param name="name">Name of the vertex channel being searched for.</param>
  212. /// <returns>Index of the vertex channel.</returns>
  213. public int IndexOf(string name)
  214. {
  215. if (string.IsNullOrEmpty(name))
  216. throw new ArgumentNullException("name");
  217. return channels.FindIndex((v) => v.Name == name);
  218. }
  219. /// <summary>
  220. /// Determines the index of the specified vertex channel.
  221. /// </summary>
  222. /// <param name="item">Vertex channel being searched for.</param>
  223. /// <returns>Index of the vertex channel.</returns>
  224. public int IndexOf(VertexChannel item)
  225. {
  226. if (item == null)
  227. throw new ArgumentNullException("item");
  228. return channels.IndexOf(item);
  229. }
  230. /// <summary>
  231. /// Inserts a new vertex channel at the specified position.
  232. /// </summary>
  233. /// <typeparam name="ElementType">Type of the new channel.</typeparam>
  234. /// <param name="index">Index for channel insertion.</param>
  235. /// <param name="name">Name of the new channel.</param>
  236. /// <param name="channelData">The new channel.</param>
  237. /// <returns>The inserted vertex channel.</returns>
  238. public VertexChannel<ElementType> Insert<ElementType>(int index, string name, IEnumerable<ElementType> channelData)
  239. {
  240. if ((index < 0) || (index > channels.Count))
  241. throw new ArgumentOutOfRangeException("index");
  242. if (string.IsNullOrEmpty(name))
  243. throw new ArgumentNullException("name");
  244. // Don't insert a channel with the same name
  245. if (IndexOf(name) >= 0)
  246. throw new ArgumentException("Vertex channel with name " + name + " already exists");
  247. VertexChannel<ElementType> channel = new VertexChannel<ElementType>(name);
  248. if (channelData != null)
  249. {
  250. // Insert the values from the enumerable into the channel
  251. channel.InsertRange(0, channelData);
  252. // Make sure we have the right number of vertices
  253. if (channel.Count != vertexContent.VertexCount)
  254. throw new ArgumentOutOfRangeException("channelData");
  255. }
  256. else
  257. {
  258. // Insert enough default values to fill the channel
  259. channel.InsertRange(0, new ElementType[vertexContent.VertexCount]);
  260. }
  261. channels.Insert(index, channel);
  262. return channel;
  263. }
  264. /// <summary>
  265. /// Inserts a new vertex channel at the specified position.
  266. /// </summary>
  267. /// <param name="index">Index for channel insertion.</param>
  268. /// <param name="name">Name of the new channel.</param>
  269. /// <param name="elementType">Type of the new channel.</param>
  270. /// <param name="channelData">Initial data for the new channel. If null, it is filled with the default value.</param>
  271. /// <returns>The inserted vertex channel.</returns>
  272. public VertexChannel Insert(int index, string name, Type elementType, IEnumerable channelData)
  273. {
  274. // Call the generic version of this method
  275. return (VertexChannel)GetType().GetMethod("Insert").MakeGenericMethod(elementType).Invoke(this, new object[] { index, name, channelData });
  276. }
  277. /// <summary>
  278. /// Removes the specified vertex channel from the collection.
  279. /// </summary>
  280. /// <param name="name">Name of the vertex channel being removed.</param>
  281. /// <returns>true if the channel was removed; false otherwise.</returns>
  282. public bool Remove(string name)
  283. {
  284. int index = IndexOf(name);
  285. if (index >= 0)
  286. {
  287. channels.RemoveAt(index);
  288. return true;
  289. }
  290. return false;
  291. }
  292. /// <summary>
  293. /// Removes the specified vertex channel from the collection.
  294. /// </summary>
  295. /// <param name="item">The vertex channel being removed.</param>
  296. /// <returns>true if the channel was removed; false otherwise.</returns>
  297. public bool Remove(VertexChannel item)
  298. {
  299. return channels.Remove(item);
  300. }
  301. /// <summary>
  302. /// Removes the vertex channel at the specified index position.
  303. /// </summary>
  304. /// <param name="index">Index of the vertex channel being removed.</param>
  305. public void RemoveAt(int index)
  306. {
  307. channels.RemoveAt(index);
  308. }
  309. /// <summary>
  310. /// Adds a new vertex channel to the collection.
  311. /// </summary>
  312. /// <param name="item">Vertex channel to be added.</param>
  313. void ICollection<VertexChannel>.Add(VertexChannel item)
  314. {
  315. channels.Add(item);
  316. }
  317. /// <summary>
  318. /// Copies the elements of the collection to an array, starting at the specified index.
  319. /// </summary>
  320. /// <param name="array">The destination array.</param>
  321. /// <param name="arrayIndex">The index at which to begin copying elements.</param>
  322. void ICollection<VertexChannel>.CopyTo(VertexChannel[] array, int arrayIndex)
  323. {
  324. channels.CopyTo(array, arrayIndex);
  325. }
  326. /// <summary>
  327. /// Inserts an item at the specified index.
  328. /// </summary>
  329. /// <param name="index">The zero-based index at which item should be inserted.</param>
  330. /// <param name="item">The item to insert.</param>
  331. void IList<VertexChannel>.Insert(int index, VertexChannel item)
  332. {
  333. channels.Insert(index, item);
  334. }
  335. /// <summary>
  336. /// Returns an enumerator that iterates through a collection.
  337. /// </summary>
  338. /// <returns>An object that can be used to iterate through the collection.</returns>
  339. IEnumerator IEnumerable.GetEnumerator()
  340. {
  341. return channels.GetEnumerator();
  342. }
  343. }
  344. }