Files
LuaCsForBarotraumaEP/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/VertexChannelCollection.cs
2019-06-25 16:00:44 +03:00

379 lines
15 KiB
C#

// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
{
/// <summary>
/// Provides methods and properties for managing a list of vertex data channels.
/// </summary>
public sealed class VertexChannelCollection : IList<VertexChannel>, ICollection<VertexChannel>, IEnumerable<VertexChannel>, IEnumerable
{
List<VertexChannel> channels;
VertexContent vertexContent;
/// <summary>
/// Gets the number of vertex channels in the collection.
/// </summary>
public int Count
{
get
{
return channels.Count;
}
}
/// <summary>
/// Gets or sets the vertex channel at the specified index position.
/// </summary>
public VertexChannel this[int index]
{
get
{
return channels[index];
}
set
{
channels[index] = value;
}
}
/// <summary>
/// Gets or sets the vertex channel with the specified name.
/// </summary>
public VertexChannel this[string name]
{
get
{
var index = IndexOf(name);
if (index < 0)
throw new ArgumentException("name");
return channels[index];
}
set
{
var index = IndexOf(name);
if (index < 0)
throw new ArgumentException("name");
channels[index] = value;
}
}
/// <summary>
/// Determines whether the collection is read-only.
/// </summary>
bool ICollection<VertexChannel>.IsReadOnly
{
get
{
return false;
}
}
/// <summary>
/// Creates an instance of VertexChannelCollection.
/// </summary>
/// <param name="vertexContent">The VertexContent object that owns this collection.</param>
internal VertexChannelCollection(VertexContent vertexContent)
{
this.vertexContent = vertexContent;
channels = new List<VertexChannel>();
_insertOverload = GetType().GetMethods().First(m => m.Name == "Insert" && m.IsGenericMethodDefinition);
}
/// <summary>
/// Adds a new vertex channel to the end of the collection.
/// </summary>
/// <typeparam name="ElementType">Type of the channel.</typeparam>
/// <param name="name">Name of the new channel.</param>
/// <param name="channelData">Initial data for the new channel. If null, the channel is filled with the default value for that type.</param>
/// <returns>The newly added vertex channel.</returns>
public VertexChannel<ElementType> Add<ElementType>(string name, IEnumerable<ElementType> channelData)
{
return Insert(channels.Count, name, channelData);
}
/// <summary>
/// Adds a new vertex channel to the end of the collection.
/// </summary>
/// <param name="name">Name of the new channel.</param>
/// <param name="elementType">Type of data to be contained in the new channel.</param>
/// <param name="channelData">Initial data for the new channel. If null, the channel is filled with the default value for that type.</param>
/// <returns>The newly added vertex channel.</returns>
public VertexChannel Add(string name, Type elementType, IEnumerable channelData)
{
return Insert(channels.Count, name, elementType, channelData);
}
/// <summary>
/// Removes all vertex channels from the collection.
/// </summary>
public void Clear()
{
channels.Clear();
}
/// <summary>
/// Determines whether the collection contains the specified vertex channel.
/// </summary>
/// <param name="name">Name of the channel being searched for.</param>
/// <returns>true if the channel was found; false otherwise.</returns>
public bool Contains(string name)
{
return channels.Exists(c => { return c.Name == name; });
}
/// <summary>
/// Determines whether the collection contains the specified vertex channel.
/// </summary>
/// <param name="item">The channel being searched for.</param>
/// <returns>true if the channel was found; false otherwise.</returns>
public bool Contains(VertexChannel item)
{
return channels.Contains(item);
}
/// <summary>
/// Converts the channel, at the specified index, to another vector format.
/// </summary>
/// <typeparam name="TargetType">Type of the target format. Can be one of the following: Single, Vector2, Vector3, Vector4, IPackedVector</typeparam>
/// <param name="index">Index of the channel to be converted.</param>
/// <returns>New channel in the specified format.</returns>
public VertexChannel<TargetType> ConvertChannelContent<TargetType>(int index)
{
if (index < 0 || index >= channels.Count)
throw new ArgumentOutOfRangeException("index");
// Get the channel at that index
var channel = this[index];
// Remove it because we cannot add a new channel with the same name
RemoveAt(index);
VertexChannel<TargetType> result = null;
try
{
// Insert a new converted channel at the same index
result = Insert(index, channel.Name, channel.ReadConvertedContent<TargetType>());
}
catch
{
// If anything went wrong, put the old channel back...
channels.Insert(index, channel);
// ...before throwing the exception again
throw;
}
// Return the new converted channel
return result;
}
/// <summary>
/// Converts the channel, specified by name to another vector format.
/// </summary>
/// <typeparam name="TargetType">Type of the target format. Can be one of the following: Single, Vector2, Vector3, Vector4, IPackedVector</typeparam>
/// <param name="name">Name of the channel to be converted.</param>
/// <returns>New channel in the specified format.</returns>
public VertexChannel<TargetType> ConvertChannelContent<TargetType>(string name)
{
var index = IndexOf(name);
if (index < 0)
throw new ArgumentException("name");
return ConvertChannelContent<TargetType>(index);
}
/// <summary>
/// Gets the vertex channel with the specified index and content type.
/// </summary>
/// <typeparam name="T">Type of a vertex channel.</typeparam>
/// <param name="index">Index of a vertex channel.</param>
/// <returns>The vertex channel.</returns>
public VertexChannel<T> Get<T>(int index)
{
if (index < 0 || index >= channels.Count)
throw new ArgumentOutOfRangeException("index");
var channel = this[index];
// Make sure the channel type is as expected
if (channel.ElementType != typeof(T))
throw new InvalidOperationException("Mismatched channel type");
return (VertexChannel<T>)channel;
}
/// <summary>
/// Gets the vertex channel with the specified name and content type.
/// </summary>
/// <typeparam name="T">Type of the vertex channel.</typeparam>
/// <param name="name">Name of a vertex channel.</param>
/// <returns>The vertex channel.</returns>
public VertexChannel<T> Get<T>(string name)
{
var index = IndexOf(name);
if (index < 0)
throw new ArgumentException("name");
return Get<T>(index);
}
/// <summary>
/// Gets an enumerator that iterates through the vertex channels of a collection.
/// </summary>
/// <returns>Enumerator for the collection.</returns>
public IEnumerator<VertexChannel> GetEnumerator()
{
return channels.GetEnumerator();
}
/// <summary>
/// Determines the index of a vertex channel with the specified name.
/// </summary>
/// <param name="name">Name of the vertex channel being searched for.</param>
/// <returns>Index of the vertex channel.</returns>
public int IndexOf(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
return channels.FindIndex((v) => v.Name == name);
}
/// <summary>
/// Determines the index of the specified vertex channel.
/// </summary>
/// <param name="item">Vertex channel being searched for.</param>
/// <returns>Index of the vertex channel.</returns>
public int IndexOf(VertexChannel item)
{
if (item == null)
throw new ArgumentNullException("item");
return channels.IndexOf(item);
}
/// <summary>
/// Inserts a new vertex channel at the specified position.
/// </summary>
/// <typeparam name="ElementType">Type of the new channel.</typeparam>
/// <param name="index">Index for channel insertion.</param>
/// <param name="name">Name of the new channel.</param>
/// <param name="channelData">The new channel.</param>
/// <returns>The inserted vertex channel.</returns>
public VertexChannel<ElementType> Insert<ElementType>(int index, string name, IEnumerable<ElementType> channelData)
{
if ((index < 0) || (index > channels.Count))
throw new ArgumentOutOfRangeException("index");
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
// Don't insert a channel with the same name
if (IndexOf(name) >= 0)
throw new ArgumentException("Vertex channel with name " + name + " already exists");
var channel = new VertexChannel<ElementType>(name);
if (channelData != null)
{
// Insert the values from the enumerable into the channel
channel.InsertRange(0, channelData);
// Make sure we have the right number of vertices
if (channel.Count != vertexContent.VertexCount)
throw new ArgumentOutOfRangeException("channelData");
}
else
{
// Insert enough default values to fill the channel
channel.InsertRange(0, new ElementType[vertexContent.VertexCount]);
}
channels.Insert(index, channel);
return channel;
}
// this reference the above Insert method and is initialized in the constructor
private readonly MethodInfo _insertOverload;
/// <summary>
/// Inserts a new vertex channel at the specified position.
/// </summary>
/// <param name="index">Index for channel insertion.</param>
/// <param name="name">Name of the new channel.</param>
/// <param name="elementType">Type of the new channel.</param>
/// <param name="channelData">Initial data for the new channel. If null, it is filled with the default value.</param>
/// <returns>The inserted vertex channel.</returns>
public VertexChannel Insert(int index, string name, Type elementType, IEnumerable channelData)
{
// Call the generic version of this method
return (VertexChannel) _insertOverload.MakeGenericMethod(elementType).Invoke(this, new object[] { index, name, channelData });
}
/// <summary>
/// Removes the specified vertex channel from the collection.
/// </summary>
/// <param name="name">Name of the vertex channel being removed.</param>
/// <returns>true if the channel was removed; false otherwise.</returns>
public bool Remove(string name)
{
var index = IndexOf(name);
if (index >= 0)
{
channels.RemoveAt(index);
return true;
}
return false;
}
/// <summary>
/// Removes the specified vertex channel from the collection.
/// </summary>
/// <param name="item">The vertex channel being removed.</param>
/// <returns>true if the channel was removed; false otherwise.</returns>
public bool Remove(VertexChannel item)
{
return channels.Remove(item);
}
/// <summary>
/// Removes the vertex channel at the specified index position.
/// </summary>
/// <param name="index">Index of the vertex channel being removed.</param>
public void RemoveAt(int index)
{
channels.RemoveAt(index);
}
/// <summary>
/// Adds a new vertex channel to the collection.
/// </summary>
/// <param name="item">Vertex channel to be added.</param>
void ICollection<VertexChannel>.Add(VertexChannel item)
{
channels.Add(item);
}
/// <summary>
/// Copies the elements of the collection to an array, starting at the specified index.
/// </summary>
/// <param name="array">The destination array.</param>
/// <param name="arrayIndex">The index at which to begin copying elements.</param>
void ICollection<VertexChannel>.CopyTo(VertexChannel[] array, int arrayIndex)
{
channels.CopyTo(array, arrayIndex);
}
/// <summary>
/// Inserts an item at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which item should be inserted.</param>
/// <param name="item">The item to insert.</param>
void IList<VertexChannel>.Insert(int index, VertexChannel item)
{
channels.Insert(index, item);
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>An object that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return channels.GetEnumerator();
}
}
}