using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace Veldrid.Common { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Padding { public float Left; public float Top; public float Right; public float Bottom; public Padding(float left = 0, float top = 0, float right = 0, float bottom = 0) { Left = left; Top = top; Right = right; Bottom = bottom; } public Padding(float all = 0) : this(all, all, all, all) { } public static Padding Zero { get; } = new Padding(); public static UInt32 Size { get; } = (uint)Unsafe.SizeOf(); } public abstract class BaseVeldridRender { internal Matrix4x4 OrthographicMatrix { get; private set; } private Matrix4x4 _ymirror = new Matrix4x4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); internal Matrix4x4 GetLineMatrix(float h = 1, float v = 1,float hoffset=0,float voffset=0) { float windowwidth = MainSwapchainBuffer.Width; float windowheight = MainSwapchainBuffer.Height; float width = windowwidth - (Margin.Left + Margin.Right); float height = windowheight - (Margin.Top + Margin.Bottom); float hscale = width / Range.XLenght * h; float vscale = height / Range.YLenght * v; var tran = Matrix4x4.CreateTranslation(0, -1 + (height / windowheight - 1), 0); return Matrix4x4.CreateScale(hscale, vscale, 1, new Vector3(-1, 1, 0)) * tran * Matrix4x4.CreateTranslation(Margin.Left * 2 / windowwidth, Margin.Top * 2 / windowheight, 0) * (!GraphicsDevice.IsClipSpaceYInverted ? _ymirror : Matrix4x4.Identity)*Matrix4x4.CreateTranslation(hoffset, voffset, 0); } public virtual void Resize() { OrthographicMatrix = GetProjMatrix(); } public LineRange Range { get; } = new LineRange(0, 10000, -5000, 5000); public SizeF ContentSize => new SizeF(MainSwapchainBuffer.Width - Margin.Left - Margin.Right, MainSwapchainBuffer.Height - Margin.Top - Margin.Bottom); private protected Matrix4x4 GetProjMatrix() { return Matrix4x4.CreateOrthographicOffCenter(0, MainSwapchainBuffer.Width, MainSwapchainBuffer.Height, 0, 0, -1); } protected Object _Locker = new Object(); public Boolean IsDisposed { get; protected set; } = false; protected CommandList CommandList { get; } private ShaderManger ShaderManger { get; } protected Framebuffer MainSwapchainBuffer => GraphicsDevice.MainSwapchain.Framebuffer; public Boolean WindowSizeState { get; set; } = true; private Dictionary propertyChangedDictionary = new Dictionary(); internal GraphicsDevice GraphicsDevice { get; } internal Vector2 WindowSize => new Vector2(GraphicsDevice.MainSwapchain.Framebuffer.Width, GraphicsDevice.MainSwapchain.Framebuffer.Height); private protected ResourceFactory ResourceFactory => GraphicsDevice.ResourceFactory; private bool TryGetPropertyState(string propertyName) { if (String.IsNullOrEmpty(propertyName)) { return false; } if (propertyChangedDictionary.TryGetValue(propertyName, out var result)) { return result; } propertyChangedDictionary[propertyName] = false; return false; } public RectangleF Rectangle => new RectangleF(Margin.Left, Margin.Top, ContentSize.Width, ContentSize.Height); public virtual bool Contains(PointF point) { if (!Visibily) return false; RectangleF rectangle = new RectangleF(Local, new SizeF(VirtualSize.X, VirtualSize.Y)); return rectangle.Contains(point); } public Padding Margin { get; set; } public virtual PointF Local { get; set; } public virtual System.Numerics.Vector2 VirtualSize { get; } internal protected Boolean this[params string[] propertyNames] { get { if (propertyNames == null || propertyNames.Length == 0) { return false; } if (propertyNames.Length == 1) { return TryGetPropertyState(propertyNames[0]); } return propertyNames.Select(x => TryGetPropertyState(x)).Any(x => x); } set { if (propertyNames == null || propertyNames.Length == 0) { return; } foreach (var name in propertyNames.Where(x => !string.IsNullOrEmpty(x))) { propertyChangedDictionary[name] = value; } } } public BaseVeldridRender(VeldridContent control) { GraphicsDevice = control.GraphicsManger.Device; CommandList = control.GraphicsManger.CommandList; ShaderManger = control.GraphicsManger.ShaderManger; Resize(); } protected void Set(ref T field, T value, [CallerMemberName] string propertyName = "") { if (object.Equals(field, value)) { return; } field = value; this[propertyName] = true; Update(propertyName, value); } internal virtual void CreateResources() { IsDisposed = false; } internal virtual void PreDraw() { } internal void Draw() { lock (_Locker) { if (Visibily && !IsDisposed) { PreDraw(); DrawData(); PosDraw(); } } } internal virtual void DrawData() { } internal virtual void PosDraw() { } internal virtual void DisposeResources() { IsDisposed = true; } internal virtual void Update(string propertyName, object value) { } private protected DeviceBuffer CreateVertexBuffer(T[] value) where T : unmanaged { var buffer = GraphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription((uint)(value.LongLength * Unsafe.SizeOf()), BufferUsage.VertexBuffer)); GraphicsDevice.UpdateBuffer(buffer, 0, value); return buffer; } private protected DeviceBuffer CreateIndexBuffer(ushort[] index) { var buffer = ResourceFactory.CreateBuffer(new BufferDescription((uint)(index.LongLength * Unsafe.SizeOf()), BufferUsage.IndexBuffer)); GraphicsDevice.UpdateBuffer(buffer, 0, index); return buffer; } private protected DeviceBuffer CreateIndexBuffer(uint[] index) { var buffer = ResourceFactory.CreateBuffer(new BufferDescription((uint)(index.LongLength * Unsafe.SizeOf()), BufferUsage.IndexBuffer)); GraphicsDevice.UpdateBuffer(buffer, 0, index); return buffer; } private protected Shader[] CreateShader(string name) { return ShaderManger.GetShaders(name); } private protected Shader GetLocalFileShader(string path, string entrypoint = "main", ShaderStages stages = ShaderStages.Vertex) => ShaderManger.GetLocalFileShader(path, entrypoint, stages); private protected Shader GetOtherShader(string name, ShaderStages stages = ShaderStages.Geometry, string entrypoints = "main") { return ShaderManger.GetOtherShader(name, stages, entrypoints); } private protected Pipeline CreatePipLine(PrimitiveTopology primitiveTopology, ResourceLayout layout, VertexLayoutDescription vertexLayout, Shader[] shaders, BlendStateDescription? blend = null, bool depthTestEnabled = true, OutputDescription? outputDescription = null, FrontFace frontFace = FrontFace.Clockwise) { return CreatePipLine(primitiveTopology, new ResourceLayout[] { layout }, new VertexLayoutDescription[] { vertexLayout }, shaders, blend, depthTestEnabled, outputDescription, frontFace); } private protected Pipeline CreatePipLine(PrimitiveTopology primitiveTopology, ResourceLayout[] layouts, VertexLayoutDescription[] vertexLayouts, Shader[] shaders, BlendStateDescription? blend = null, bool depthTestEnabled = true, OutputDescription? outputDescription = null, FrontFace frontFace = FrontFace.Clockwise) { GraphicsPipelineDescription pipelineDescription = new GraphicsPipelineDescription(); pipelineDescription.BlendState = blend ?? BlendStateDescription.SingleAlphaBlend; pipelineDescription.DepthStencilState = new DepthStencilStateDescription( depthTestEnabled: depthTestEnabled, depthWriteEnabled: true, comparisonKind: ComparisonKind.LessEqual); pipelineDescription.RasterizerState = new RasterizerStateDescription( cullMode: FaceCullMode.Back, fillMode: PolygonFillMode.Solid, frontFace: frontFace, depthClipEnabled: true, scissorTestEnabled: false); pipelineDescription.PrimitiveTopology = primitiveTopology; pipelineDescription.ResourceLayouts = layouts; pipelineDescription.Outputs = outputDescription ?? GraphicsDevice.SwapchainFramebuffer.OutputDescription; pipelineDescription.ShaderSet = new ShaderSetDescription( vertexLayouts: vertexLayouts, shaders: shaders, specializations: new[] { new SpecializationConstant(0, GraphicsDevice.IsClipSpaceYInverted) }); return ResourceFactory.CreateGraphicsPipeline(pipelineDescription); } public bool Visibily { get; set; } = true; } }