using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using Chernobyl.Collections.Generic.Event; using Chernobyl.Dependency; using Chernobyl.Graphics.Drawing; using Chernobyl.Graphics.Material; using Chernobyl.Graphics.Material.Shader.Parameters; using Chernobyl.Graphics.Polygon.Buffers; using Chernobyl.Graphics.Texture; using Chernobyl.Graphics.Writing; using Chernobyl.Graphics.Xna.Controllers; using Chernobyl.Graphics.Xna.Controllers.Shaders; using Chernobyl.Graphics.Xna.Resources; using Chernobyl.Graphics.Xna.Texture; using Chernobyl.Graphics.Xna.Writing; using Chernobyl.Plugin; using Chernobyl.Resources; using Microsoft.Xna.Framework.Graphics; namespace Chernobyl.Graphics.Xna { /// <summary> /// The XNA graphics plug-in for Chernobyl.Graphics. /// </summary> public class XnaPlugin : IPlugin { /// <summary> /// Constructor. /// </summary> /// <param name="services">The <see cref="IEventCollection{T}"/> instance that /// gives and takes services.</param> public XnaPlugin(IEventCollection<object> services) { Trace = new TraceSource("Chernobyl.Graphics.Xna"); Services = services; services.Add((MeshFactoryServiceCreator)XnaMeshFactoryServiceCreator); services.Add((IndexBufferFactoryServiceCreator)XnaIndexBufferServiceCreator); RenderFactory = (serv, primType, drawable, transform, volume) => new XnaRender(serv, primType, drawable, transform, volume); Texture2DFactory = (serv, width, height, mipmapLevels, textureFormat) => new XnaTexture2D(serv, width, height, mipmapLevels, textureFormat); BackBuffer = new XnaBackBuffer(); TextureParameterFactory = (serv, val, paramName) => new XnaTextureParameter(serv, val, paramName); BasicEffectFactory = (serv) => new Effects.BasicEffect(serv); TextFactory = (serv, font) => new XnaText(serv, font); // Create the effect parameter converters { EffectParameterConverters = new SortedList<EffectParameterType, Func<EffectParameter, IShaderParameter>>(1); // if you add more parameters, make sure to update the capacity set in the SortedList constructor above EffectParameterConverters.Add(EffectParameterType.Texture2D, param => new XnaTextureParameter(services, new XnaTexture2D(services, param.GetValueTexture2D()), param.Name)); } services.Inject(this); } /// <summary> /// The services provided by this plug-in or null if no services are /// provided. /// </summary> public IEventCollection<object> Services { get; private set; } /// <summary> /// A <see cref="TraceSource"/> used to output errors, warnings, information, /// etc., that are specific to Chernobyl.Graphics.Xna. This /// <see cref="TraceSource"/> will have the name "Chernobyl.Graphics.Xna". /// </summary> public static TraceSource Trace { get; private set; } /// <summary> /// Holds vertex declarations that were previously created /// so that they can be re-used. /// </summary> [Provide] public IDictionary<Type, Information> VertexDeclarationStore { get { return _vertexDeclarationStore ?? (_vertexDeclarationStore = new Dictionary<Type, Information>()); } } /// <summary> /// Creates DrawBufferFactory controllers. /// </summary> [Provide] public IDrawBufferFactory DrawBufferFactory { get { return _drawBufferFactory ?? (_drawBufferFactory = new XnaDrawBuffer.Factory()); } } /// <summary> /// Creates IRender controllers. /// </summary> [Provide] public RenderFactory RenderFactory { get; set; } /// <summary> /// Creates Texture2D controllers /// </summary> [Provide] public Texture2DFactory Texture2DFactory { get; set; } /// <summary> /// The back buffer provided by XNA. /// </summary> [Provide] public IBackBuffer BackBuffer { get; private set; } /// <summary> /// The texture shader parameter factory. /// </summary> [Provide] public ShaderParameterFactory<ITexture> TextureParameterFactory { get; set; } /// <summary> /// The factory that creates basic effects. /// </summary> [Provide] public BasicEffectFactory BasicEffectFactory { get; set; } /// <summary> /// The factory that produces the IText instances. /// </summary> [Provide] public TextFactory TextFactory { get; set; } /// <summary> /// A <see cref="SortedList{TKey, TValue}"/> that holds mappings of an /// <see cref="EffectParameterType"/> to converter methods. These /// converter methods are responsible for converting the passed in XNA /// <see cref="EffectParameter"/> (which of type <see cref="EffectParameterType"/>) /// to a Chernobyl <see cref="IShaderParameter"/>. /// </summary> [Provide] public SortedList<EffectParameterType, Func<EffectParameter, IShaderParameter>> EffectParameterConverters { get; private set; } /// <summary> /// The root shader IResourceProcessor that was added by Chernobyl.Graphics. /// </summary> [Inject] public IResourceProcessor<IEffect> RootEffectProcessor { set { FileStreamProcessor<IEffect> effectFileStreamProcessor = value.OfType<FileStreamProcessor<IEffect>>().First(); // TODO: add in the XNA IEffect processor //effectFileStreamProcessor.FileStreamProcessors.Add("[a-zA-Z]*\\.fx", ); } } /// <summary> /// The root font resource processor. /// </summary> [Inject] public IResourceProcessor<IFont> RootFontProcessor { set { // get the resource processor at the end of the resource processing chain IResourceProcessor<IFont> lastFontProcessor = value.First(proc => proc.NextResourceProcessor == null); lastFontProcessor.NextResourceProcessor = new XnaResourceProcessor<IFont, SpriteFont>(Services, spriteFont => new XnaFont(Services, spriteFont)); } } /// <summary> /// The root texture resource processor. /// </summary> [Inject] public IResourceProcessor<ITexture> RootTextureProcessor { set { // get the resource processor at the end of the resource processing chain IResourceProcessor<ITexture> lastTextureProcessor = value.First(proc => proc.NextResourceProcessor == null); lastTextureProcessor.NextResourceProcessor = new XnaResourceProcessor<ITexture, Microsoft.Xna.Framework.Graphics.Texture2D>(Services, texture => new XnaTexture2D(Services, texture)); } } /// <summary> /// Method that creates the <see cref="MeshFactory{TData}"/>. /// </summary> /// <param name="dataType">Type of the data that will be stored in the /// <see cref="IBuffer{TData}"/> created by the <see cref="MeshFactory{TData}"/>.</param> /// <returns>The <see cref="MeshFactory{TData}"/> in the form of an /// <see cref="Object"/>.</returns> public static object XnaMeshFactoryServiceCreator(Type dataType) { MethodInfo method = typeof(XnaPlugin).GetMethod("MeshFactory").MakeGenericMethod(dataType); Type methodType = typeof (MeshFactory<>).MakeGenericType(dataType); return Delegate.CreateDelegate(methodType, method); } /// <summary> /// Method that creates the <see cref="IndexBufferFactory{TData}"/>. /// </summary> /// <param name="dataType">Type of the data.</param> /// <returns></returns> public static object XnaIndexBufferServiceCreator(Type dataType) { MethodInfo method = typeof(XnaPlugin).GetMethod("IndexBufferFactory").MakeGenericMethod(dataType); Type methodType = typeof(MeshFactory<>).MakeGenericType(dataType); return Delegate.CreateDelegate(methodType, method); } /// <summary> /// A method that creates meshes that interface with XNA vertex buffers. /// </summary> /// <typeparam name="TData">The type of data that is going to be stored in /// the buffer like ints, floats, shorts, a custom mesh element type, etc.</typeparam> /// <param name="services">The list of services to inject into this buffer.</param> /// <param name="meshElements">The mesh element data to place in the mesh.</param> /// <returns>The <see cref="IBuffer{TData}"/> that represents the mesh.</returns> public static IBuffer<TData> MeshFactory<TData>(IEventCollection<object> services, TData[] meshElements) where TData : struct { return new XnaMesh<TData>(services, meshElements); } /// <summary> /// A method that creates index buffer that interface with XNA index buffers. /// </summary> /// <typeparam name="TData">The type of data that is going to be stored in /// the buffer like ints, floats, shorts, a custom mesh element type, etc.</typeparam> /// <param name="services">The list of services to inject into this buffer.</param> /// <param name="indices">The index data to place in this buffer.</param> /// <returns>The <see cref="IBuffer{TData}"/> that represents the mesh.</returns> public static IBuffer<TData> IndexBufferFactory<TData>(IEventCollection<object> services, TData[] indices) where TData : struct { return new XnaIndexBuffer<TData>(services, indices); } /// <summary> /// The backing field to <see cref="VertexDeclarationStore"/>. /// </summary> IDictionary<Type, Information> _vertexDeclarationStore; /// <summary> /// The backing field to <see cref="DrawBufferFactory"/>. /// </summary> IDrawBufferFactory _drawBufferFactory; } }