diff --git a/SomeChartsAvaloniaExamples/Program.cs b/SomeChartsAvaloniaExamples/Program.cs index a70400e..6a3aea9 100644 --- a/SomeChartsAvaloniaExamples/Program.cs +++ b/SomeChartsAvaloniaExamples/Program.cs @@ -6,6 +6,6 @@ namespace SomeChartsAvaloniaExamples; internal class Program { [STAThread] public static void Main(string[] args) { - ElementsExamples.RunLabel(); + ElementsExamples.RunLineChart(); } } \ No newline at end of file diff --git a/SomeChartsAvaloniaExamples/src/elements/ElementsExamples.cs b/SomeChartsAvaloniaExamples/src/elements/ElementsExamples.cs index 489e605..ebd5fa6 100644 --- a/SomeChartsAvaloniaExamples/src/elements/ElementsExamples.cs +++ b/SomeChartsAvaloniaExamples/src/elements/ElementsExamples.cs @@ -149,28 +149,29 @@ public static class ElementsExamples { public static void RunLineChart() { AvaloniaRunUtils.RunAfterStart(() => { - AvaloniaChartsCanvas canvas = AvaloniaRunUtils.AddCanvas(); + AvaloniaGlChartsCanvas canvas = AvaloniaRunUtils.AddGlCanvas(); const int rulerOffset = 1_000_000; - canvas.AddElement(new Ruler(canvas.canvas) { - drawLabels = true, - orientation = Orientation.horizontal, - length = rulerOffset, - names = new FuncChartManagedData(i => i.ToString(), 1), - stickRange = new(0, 0, 0, rulerOffset) - }); + // canvas.AddElement(new Ruler(canvas.canvas) { + // drawLabels = true, + // orientation = Orientation.horizontal, + // length = rulerOffset, + // names = new FuncChartManagedData(i => i.ToString(), 1), + // stickRange = new(0, 0, 0, rulerOffset) + // }); + // + // canvas.AddElement(new Ruler(canvas.canvas) { + // drawLabels = true, + // orientation = Orientation.vertical, + // length = rulerOffset, + // names = new FuncChartManagedData(i => (i * 100).ToString(), 1), + // stickRange = new(0, 0, rulerOffset, 0) + // }); - canvas.AddElement(new Ruler(canvas.canvas) { - drawLabels = true, - orientation = Orientation.vertical, - length = rulerOffset, - names = new FuncChartManagedData(i => (i * 100).ToString(), 1), - stickRange = new(0, 0, rulerOffset, 0) - }); + IChartData data = new FuncChartData(i => MathF.Sin(i * .1f) * 1000, 20480); + IChartData colors = new ConstChartData(new(theme.bad_ind)); - IChartData data = new FuncChartData(i => MathF.Sin(i * .1f) * 1000, 2048); - IChartData colors = new ConstChartData(new(theme.good_ind)); - canvas.AddElement(new LineChart(data, colors, canvas.canvas)); + canvas.AddElement(new LineChart(data, colors, canvas.canvas) {isDynamic = true}); }); AvaloniaRunUtils.RunAvalonia(); diff --git a/SomeChartsUi/src/elements/charts/line/LineChart.cs b/SomeChartsUi/src/elements/charts/line/LineChart.cs index 06a2f86..4ccfcd6 100644 --- a/SomeChartsUi/src/elements/charts/line/LineChart.cs +++ b/SomeChartsUi/src/elements/charts/line/LineChart.cs @@ -1,3 +1,5 @@ +using MathStuff; +using MathStuff.vectors; using SomeChartsUi.data; using SomeChartsUi.themes.colors; using SomeChartsUi.ui.canvas; @@ -24,33 +26,33 @@ public class LineChart : RenderableBase, IDownsample { public float downsampleMultiplier { get; set; } = .5f; public float elementScale { get; set; } = 100; - protected override void GenerateMesh() { } - // protected override unsafe void Render() { - // int length = values.GetLength(); - // if (length < 1) return; - // - // int downsample = GetDownsample(orientation, downsampleMultiplier); - // (float startPos, float endPos) culledPositions = GetStartEndPos(float2.zero, length * elementScale, orientation); - // (float start, int count) = GetStartCountIndexes(culledPositions, elementScale * (1 << downsample)); - // int startIndex = (int)(start / elementScale); - // - // if (count <= 1) return; - // - // float2 vec = GetOrientationVector(orientation); - // - // // get line points - // float2* linePoints = stackalloc float2[count]; - // float* pointHeightsStart = (float*)linePoints + (int) vec.x; - // float* pointWidthStart = (float*)linePoints + (int) vec.y; - // values.GetValuesWithStride(startIndex, count, downsample, pointHeightsStart, 2); - // for (int i = 0; i < count; i++) - // pointWidthStart[i << 1] = (startIndex + (i << downsample)) * elementScale; - // - // // get line colors - // color* lineColors = stackalloc color[count]; - // colors.GetColors(startIndex, count, downsample, lineColors); - // - // DrawConnectedLines(linePoints, lineColors, lineThickness.Get(this), count - 1, lineAlphaMul.Get(this)); - // DrawPoints(linePoints, lineColors, pointThickness.Get(this), count - 1); - // } + protected override unsafe void GenerateMesh() { + mesh!.Clear(); + + int length = values.GetLength(); + if (length < 1) return; + int downsample = GetDownsample(orientation, downsampleMultiplier); + (float startPos, float endPos) culledPositions = GetStartEndPos(float2.zero, length * elementScale, orientation); + (float start, int count) = GetStartCountIndexes(culledPositions, elementScale * (1 << downsample)); + int startIndex = (int)(start / elementScale); + if (count <= 1) return; + float2 vec = GetOrientationVector(orientation); + + // get line points + float2* linePoints = stackalloc float2[count]; + float* pointHeightsStart = (float*)linePoints + (int) vec.x; + float* pointWidthStart = (float*)linePoints + (int) vec.y; + values.GetValuesWithStride(startIndex, count, downsample, pointHeightsStart, 2); + for (int i = 0; i < count; i++) + pointWidthStart[i << 1] = (startIndex + (i << downsample)) * elementScale; + + // get line colors + color* lineColors = stackalloc color[count]; + colors.GetColors(startIndex, count, downsample, lineColors); + + AddPoints(mesh, linePoints, lineColors, pointThickness.Get(this), count - 1); + AddConnectedLines(mesh!, linePoints, lineColors, lineThickness.Get(this), count - 1, lineAlphaMul.Get(this)); + + mesh.OnModified(); + } } \ No newline at end of file diff --git a/SomeChartsUi/src/ui/canvas/ChartCanvasTransform.cs b/SomeChartsUi/src/ui/canvas/ChartCanvasTransform.cs index 1b19fb1..fc1046a 100644 --- a/SomeChartsUi/src/ui/canvas/ChartCanvasTransform.cs +++ b/SomeChartsUi/src/ui/canvas/ChartCanvasTransform.cs @@ -27,8 +27,8 @@ public class ChartCanvasTransform { scale.OnUpdate(deltaTime); rotation.OnUpdate(deltaTime); - worldBounds = screenBounds.ToWorld(position, scale); - + //worldBounds = screenBounds.ToWorld(-position.animatedValue, scale); + worldBounds = new(screenBounds.left + position.animatedValue.x - screenBounds.width / 2 / scale.animatedValue.x, screenBounds.bottom + position.animatedValue.y, screenBounds.width / scale.animatedValue.x, screenBounds.height / scale.animatedValue.y); RecalculateMatrix(); } diff --git a/SomeChartsUi/src/ui/elements/RenderableBaseDraw.cs b/SomeChartsUi/src/ui/elements/RenderableBaseDraw.cs index 062eab5..5442d6b 100644 --- a/SomeChartsUi/src/ui/elements/RenderableBaseDraw.cs +++ b/SomeChartsUi/src/ui/elements/RenderableBaseDraw.cs @@ -1,9 +1,76 @@ +using MathStuff; using MathStuff.vectors; using SomeChartsUi.elements; +using SomeChartsUi.utils.mesh; namespace SomeChartsUi.ui.elements; public abstract partial class RenderableBase { + protected unsafe void AddConnectedLines(Mesh m, float2* linePoints, color* lineColors, float thickness, int len, float alphaMul = 1) { + int vCount = len * 4; + int iCount = len * 6; + + m.vertices.EnsureFreeSpace(vCount); + m.indexes.EnsureFreeSpace(iCount); + + int curVIndex = m.vertices.count; + for (int i = 0; i < len; i++) { + float2 p0 = linePoints[i]; + float2 p1 = linePoints[i + 1]; + color c0 = lineColors[i]; + c0.aF *= alphaMul; + + float2 offset = Rot90DegFastWithLen(p0 - p1, thickness); + + m.AddVertex(new(new(p1.x - offset.x, p1.y - offset.y), float3.front, float2.zero, c0)); + m.AddVertex(new(new(p1.x + offset.x, p1.y + offset.y), float3.front, float2.zero, c0)); + m.AddVertex(new(new(p0.x + offset.x, p0.y + offset.y), float3.front, float2.zero, c0)); + m.AddVertex(new(new(p0.x - offset.x, p0.y - offset.y), float3.front, float2.zero, c0)); + + m.AddIndex(curVIndex + 0); + m.AddIndex(curVIndex + 1); + m.AddIndex(curVIndex + 2); + m.AddIndex(curVIndex + 0); + m.AddIndex(curVIndex + 2); + m.AddIndex(curVIndex + 3); + + curVIndex += 4; + } + + //m.vertices.Add(); +// + //DrawVertices(points, null, colors, indexes, vCount, iCount); + } + + protected unsafe void AddPoints(Mesh m, float2* elementPoints, color* elementColors, float size, int len) { + int vCount = len * 4; + int iCount = len * 6; + + m.vertices.EnsureFreeSpace(vCount); + m.indexes.EnsureFreeSpace(iCount); + + int curVIndex = m.vertices.count; + for (int i = 0; i < len; i++) { + float2 p0 = elementPoints[i]; + color c0 = elementColors[i]; + + m.AddVertex(new(new(p0.x - size, p0.y - size), float3.front, float2.zero, c0)); + m.AddVertex(new(new(p0.x - size, p0.y + size), float3.front, float2.zero, c0)); + m.AddVertex(new(new(p0.x + size, p0.y + size), float3.front, float2.zero, c0)); + m.AddVertex(new(new(p0.x + size, p0.y - size), float3.front, float2.zero, c0)); + + m.AddIndex(curVIndex + 0); + m.AddIndex(curVIndex + 1); + m.AddIndex(curVIndex + 2); + m.AddIndex(curVIndex + 0); + m.AddIndex(curVIndex + 2); + m.AddIndex(curVIndex + 3); + + curVIndex += 4; + } + } + + /* /// draws non-connected lines /// first and second points of lines
the length is 2 * lineCount /// first and second point colors of lines
the length is 2 * lineCount diff --git a/SomeChartsUi/src/ui/elements/RenderableBaseUtils.cs b/SomeChartsUi/src/ui/elements/RenderableBaseUtils.cs index 930dfb9..c0a10a9 100644 --- a/SomeChartsUi/src/ui/elements/RenderableBaseUtils.cs +++ b/SomeChartsUi/src/ui/elements/RenderableBaseUtils.cs @@ -61,6 +61,8 @@ public abstract partial class RenderableBase { protected (float start, float end) GetStartEndPos(float startLim, float endLim, Orientation orientation) { float2 s = 1 / canvasScale; Transform tr = transform; + //Console.WriteLine(startLim + " " + endLim + " " + math.min(endLim, canvas.transform.worldBounds.right*10 - tr.position.x)); + //return (math.max(startLim, canvas.transform.worldBounds.left - tr.position.x), math.min(endLim, canvas.transform.worldBounds.right - tr.position.x)); if ((orientation & Orientation.vertical) != 0) return (orientation & Orientation.reversed) != 0 ? (math.max(startLim, canvas.transform.worldBounds.top - tr.position.y), math.min(endLim, canvas.transform.worldBounds.bottom - tr.position.y)) diff --git a/SomeChartsUi/src/utils/mesh/Mesh.cs b/SomeChartsUi/src/utils/mesh/Mesh.cs index 3be707c..06d873f 100644 --- a/SomeChartsUi/src/utils/mesh/Mesh.cs +++ b/SomeChartsUi/src/utils/mesh/Mesh.cs @@ -53,6 +53,9 @@ public class Mesh : IDisposable { } } + public void AddVertex(Vertex v) => vertices.Add(v); + public void AddIndex(int v) => indexes.Add((ushort) v); + public unsafe void RecalculateNormals() { int c = indexes.count; diff --git a/SomeChartsUiAvalonia/src/controls/gl/AvaloniaGlChartsCanvas.cs b/SomeChartsUiAvalonia/src/controls/gl/AvaloniaGlChartsCanvas.cs index 8c9ba7d..8a818bb 100644 --- a/SomeChartsUiAvalonia/src/controls/gl/AvaloniaGlChartsCanvas.cs +++ b/SomeChartsUiAvalonia/src/controls/gl/AvaloniaGlChartsCanvas.cs @@ -33,7 +33,10 @@ public class AvaloniaGlChartsCanvas : CustomGlControlBase { public AvaloniaGlChartsCanvas() { _updateTimer = new(_ => { - try { Dispatcher.UIThread?.RunJobs(); } + try { + if (Dispatcher.UIThread.CheckAccess()) + Dispatcher.UIThread?.RunJobs(); + } catch (Exception e) {// ignored } }, null, 0, 1000 / 50); diff --git a/SomeChartsUiAvalonia/src/utils/collections/GlMesh.cs b/SomeChartsUiAvalonia/src/utils/collections/GlMesh.cs index 199c4fd..f673364 100644 --- a/SomeChartsUiAvalonia/src/utils/collections/GlMesh.cs +++ b/SomeChartsUiAvalonia/src/utils/collections/GlMesh.cs @@ -68,7 +68,7 @@ public class GlMesh : Mesh { else { List changes = vertices.GetChanges(); foreach (Range r in changes) - GlInfo.glExt!.BufferSubData(GL_ARRAY_BUFFER, r.Start.Value * vSize, (r.End.Value - r.Start.Value) * vSize, vertices.dataPtr); + GlInfo.glExt!.BufferSubData(GL_ARRAY_BUFFER, r.Start.Value * vSize, (r.End.Value - r.Start.Value) * vSize, vertices.dataPtr + r.Start.Value); } // indexes @@ -82,7 +82,7 @@ public class GlMesh : Mesh { else { List changes = indexes.GetChanges(); foreach (Range r in changes) - GlInfo.glExt!.BufferSubData(GL_ELEMENT_ARRAY_BUFFER, r.Start.Value * iSize, (r.End.Value - r.Start.Value) * iSize, indexes.dataPtr); + GlInfo.glExt!.BufferSubData(GL_ELEMENT_ARRAY_BUFFER, r.Start.Value * iSize, (r.End.Value - r.Start.Value) * iSize, indexes.dataPtr + r.Start.Value); } updateRequired = false;