using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Text; namespace Veldrid.Common.Axis { public sealed class LineAxis : BaseVeldridRender,IZoomRender { public float HScale { get; set; } = 1; public float VScale { get; set; } = 1; public float HOffset { get; set; } public float VOffset { get; set; } public bool ZoomEnbled { get; set; } = true; public Vector2 WindowScale { get; set; } = Vector2.One; struct ProjView { public Matrix4x4 Proj; public Matrix4x4 View; } private ProjView projView; Pipeline borderpipeline; Pipeline pipeline; DeviceBuffer plotInfoBuffer; DeviceBuffer projViewBuffer; DeviceBuffer dataBuffer; ResourceLayout infoLayout; ResourceSet infoSet; Shader[] shaders; MutiText text; private object locker = new object(); public LineAxis(VeldridContent control) : base(control) { Margin = new Padding(38, 8, 8, 18); text = new MutiText(control,true,true); text.CreateResources(); text.FontSize = 10; text.TextInfos = Enumerable.Range(0, 22).Select(x => new TextInfo()).ToArray(); text.Margin = new Padding(40,10,10,20); } internal override void DisposeResources() { base.DisposeResources(); borderpipeline?.Dispose(); pipeline?.Dispose(); plotInfoBuffer?.Dispose(); projViewBuffer?.Dispose(); dataBuffer?.Dispose(); infoLayout?.Dispose(); infoSet?.Dispose(); text?.DisposeResources(); } internal override void CreateResources() { base.CreateResources(); Vector2[] positon = new Vector2[5 + 44]; positon[0] = new Vector2(Range.MinX, Range.MaxY); positon[1] = new Vector2(Range.MaxX, Range.MaxY); positon[2] = new Vector2(Range.MaxX, Range.MinY); positon[3] = new Vector2(Range.MinX, Range.MinY); positon[4] = positon[0]; for (int i = 0; i < 11; i++) { positon[5 + i * 2] = new Vector2(Range.MinX + Range.XLenght / 10 * i, Range.MinY); positon[5 + i * 2 + 1] = new Vector2(Range.MinX + Range.XLenght / 10 * i, Range.MaxY); positon[5 + i * 2 + 22] = new Vector2(Range.MinX, Range.MinY + Range.YLenght / 10 * i); positon[5 + i * 2 + 1 + 22] = new Vector2(Range.MaxX, Range.MinY + Range.YLenght / 10 * i); } for (int i = 0; i < 11; i++) { text.TextInfos[i].Color = RgbaFloat.White; text.TextInfos[i].HorizontalAlignment = HorizontalAlignment.Center; text.TextInfos[i].VerticalAlignment = VerticalAlignment.Top; text.TextInfos[i].Local = new PointF(Range.MinX + i * (Range.XLenght / 10), Range.MinY); text.TextInfos[i + 11].Color = RgbaFloat.White; text.TextInfos[i + 11].HorizontalAlignment = HorizontalAlignment.Right; text.TextInfos[i + 11].VerticalAlignment = VerticalAlignment.Center; text.TextInfos[i + 11].Local = new PointF(Range.MinX-40, Range.MinY + i * (Range.YLenght / 10)); text.TextInfos[i + 11].Text = i.ToString(); } dataBuffer = ResourceFactory.CreateBuffer(new BufferDescription((uint)(Unsafe.SizeOf() * positon.Length), BufferUsage.VertexBuffer)); GraphicsDevice.UpdateBuffer(dataBuffer, 0, positon); projViewBuffer = ResourceFactory.CreateBuffer(new BufferDescription((uint)Unsafe.SizeOf(), BufferUsage.UniformBuffer)); plotInfoBuffer = ResourceFactory.CreateBuffer(new BufferDescription((uint)Unsafe.SizeOf() * 2, BufferUsage.UniformBuffer)); GraphicsDevice.UpdateBuffer(plotInfoBuffer, 0, RgbaFloat.White); infoLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("InfoBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("ProjView", ResourceKind.UniformBuffer, ShaderStages.Vertex))); infoSet = ResourceFactory.CreateResourceSet(new ResourceSetDescription(infoLayout, plotInfoBuffer, projViewBuffer)); shaders = CreateShader("LineAxis"); borderpipeline = CreatePipLine(PrimitiveTopology.LineStrip, infoLayout, new VertexLayoutDescription(new VertexElementDescription("In_Position", VertexElementFormat.Float2, VertexElementSemantic.TextureCoordinate)), shaders); pipeline = CreatePipLine(PrimitiveTopology.LineList, infoLayout, new VertexLayoutDescription(new VertexElementDescription("In_Position", VertexElementFormat.Float2, VertexElementSemantic.TextureCoordinate)), shaders); } public float LoopTime; public ulong TotalCount; public uint PlotDataLenght; private string GetTimeString(float time) { int s = (int)(time % 60); int m = (int)(time/60 % 60); int h = (int)(time / 3600); return string.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s); } internal override void DrawData() { lock (locker) { float intert = Range.XLenght / PlotDataLenght; var total = TotalCount - HOffset / (MainSwapchainBuffer.Width/WindowScale.X) * TotalCount; float offset = (total * intert) % (Range.YLenght / 10); if (TotalCount <= PlotDataLenght) offset = 0; float totaltime = LoopTime * total / 1000/HScale; float plotime = LoopTime * PlotDataLenght / 1000 / 10/HScale; float maxtime = MathF.Ceiling(total / (PlotDataLenght / 10f)) * plotime; float mintime = maxtime - plotime * 11; base.DrawData(); projView.Proj = base.OrthographicMatrix; projView.View = GetLineMatrix(); CommandList.SetFramebuffer(MainSwapchainBuffer); CommandList.UpdateBuffer(projViewBuffer, 0, projView); CommandList.SetPipeline(pipeline); CommandList.UpdateBuffer(plotInfoBuffer, 0, new RgbaFloat(0.5f,0.5f,0.5f,1)); CommandList.UpdateBuffer(plotInfoBuffer, (uint)Unsafe.SizeOf(), 0); CommandList.SetVertexBuffer(0, dataBuffer); CommandList.SetGraphicsResourceSet(0, infoSet); CommandList.Draw(22, 1, 5+22, 0); CommandList.UpdateBuffer(plotInfoBuffer, (uint)Unsafe.SizeOf(), offset); CommandList.Draw(22, 1, 5, 0); CommandList.SetPipeline(borderpipeline); CommandList.UpdateBuffer(plotInfoBuffer, 0, RgbaFloat.White); CommandList.UpdateBuffer(plotInfoBuffer, (uint)Unsafe.SizeOf(), 0f); CommandList.SetVertexBuffer(0, dataBuffer); CommandList.SetGraphicsResourceSet(0, infoSet); CommandList.Draw(5); CommandList.SetFramebuffer(MainSwapchainBuffer); float tempoffset = (VOffset * VScale) / Rectangle.Height * 10 * Range.YLenght + Range.MinY; for (int i = 0; i < 11; i++) { text.TextInfos[i].BackColor = RgbaFloat.Clear; text.TextInfos[i].Local = new PointF(Range.XLenght / 10 * i - offset, text.TextInfos[i].Local.Y); if (TotalCount <= PlotDataLenght) { text.TextInfos[i].Text = GetTimeString(i * plotime); } else { text.TextInfos[i].Text = GetTimeString(mintime + plotime * i); } text.TextInfos[i + 11].Text = Tools.SiHelper.ValueChangeToSI((Range.YLenght / 10 * i+tempoffset ) / VScale,out _,out _,1); } text.DrawData(); } } public override void Resize() { base.Resize(); text?.Resize(); } } public sealed class LineAxisConfig:BaseProperty { public double Start { get; set; } public double End { get; set; } } }