diff --git a/Cavern.QuickEQ/Graphing/Overlays/Frame.cs b/Cavern.QuickEQ/Graphing/Overlays/Frame.cs index 169239c2..a27d5bf0 100644 --- a/Cavern.QuickEQ/Graphing/Overlays/Frame.cs +++ b/Cavern.QuickEQ/Graphing/Overlays/Frame.cs @@ -1,4 +1,6 @@ -namespace Cavern.QuickEQ.Graphing.Overlays { +using System.Runtime.CompilerServices; + +namespace Cavern.QuickEQ.Graphing.Overlays { /// /// Draws a frame of a given over the graph. /// @@ -27,25 +29,40 @@ public Frame(int width, uint color) { /// Adds the overlay to a graph. /// public override void DrawOn(GraphRenderer target) { - // Edge rows + DrawRow(target, 0, Width, color); + DrawRow(target, target.Height - Width, Width, color); + DrawColumn(target, 0, Width, color); + DrawColumn(target, target.Width - Width, Width, color); + } + + /// + /// Draw a single row at a height of a developing image. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void DrawRow(GraphRenderer target, int offset, int width, uint color) { uint[] pixels = target.Pixels; - int until = target.Width * Width; - for (int i = 0; i < until; i++) { - pixels[i] = color; - } - for (int i = pixels.Length - until; i < pixels.Length; i++) { - pixels[i] = color; + while (width > 0) { + for (int y = offset * target.Width, end = y + target.Width; y < end; y++) { + pixels[y] = color; + } + offset++; + width--; } + } - // Edge columns - for (int x = 0; x < Width; x++) { - int c = target.Height - Width; - for (int y = Width; y < c; y++) { - pixels[y * target.Width + x] = color; - } - for (int y = Width; y < c; y++) { - pixels[pixels.Length - y * target.Width - x] = color; + /// + /// Draw a single column at a width of a developing image. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void DrawColumn(GraphRenderer target, int offset, int width, uint color) { + uint[] pixels = target.Pixels; + while (width > 0) { + for (int y = 0, pos = offset, step = target.Width; y < target.Height; y++) { + pixels[pos] = color; + pos += step; } + offset++; + width--; } } } diff --git a/Cavern.QuickEQ/Graphing/Overlays/Grid.cs b/Cavern.QuickEQ/Graphing/Overlays/Grid.cs index 97c9b889..1178c658 100644 --- a/Cavern.QuickEQ/Graphing/Overlays/Grid.cs +++ b/Cavern.QuickEQ/Graphing/Overlays/Grid.cs @@ -37,29 +37,15 @@ public Grid(int borderWidth, int gridWidth, uint color, int xSteps, int ySteps) /// public override void DrawOn(GraphRenderer target) { base.DrawOn(target); - uint[] pixels = target.Pixels; - int xGap = target.Width / xSteps, - yGap = target.Height / ySteps, - yMax = target.Height - Width; + + int gap = target.Width / xSteps; for (int x = 1; x < xSteps; x++) { - int xPos = x * xGap; - for (int y = Width; y <= yMax; y++) { - int start = y * target.Width + xPos; - for (int w = 0; w < gridWidth; w++) { - pixels[start + w] = color; - } - } + DrawColumn(target, x * gap, gridWidth, color); } - int xMax = target.Width - Width; + gap = target.Height / ySteps; for (int y = 1; y < ySteps; y++) { - int yPos = y * yGap; - for (int w = 0; w < gridWidth; w++) { - int start = (yPos + w) * target.Width; - for (int x = Width; x <= xMax; x++) { - pixels[start + x] = color; - } - } + DrawRow(target, y * gap, gridWidth, color); } } } diff --git a/Cavern.QuickEQ/Graphing/Overlays/LogScaleGrid.cs b/Cavern.QuickEQ/Graphing/Overlays/LogScaleGrid.cs new file mode 100644 index 00000000..e52cf960 --- /dev/null +++ b/Cavern.QuickEQ/Graphing/Overlays/LogScaleGrid.cs @@ -0,0 +1,54 @@ +using Cavern.Utilities; +using System; + +namespace Cavern.QuickEQ.Graphing.Overlays { + /// + /// Draws a grid over the graph with a gridline at every increment of the highest local value. + /// + public class LogScaleGrid : Frame { + /// + /// Inner line stroke width. + /// + readonly int gridWidth; + + /// + /// Number of rows drawn, including the frame lines. + /// + readonly int ySteps; + + /// + /// Draws a grid over the graph with a gridline at every increment of the highest local value. + /// + /// Border line stroke width + /// Inner line stroke width + /// RGBA color of the line + /// Number of rows drawn, including the frame lines + public LogScaleGrid(int borderWidth, int gridWidth, uint color, int ySteps) : base(borderWidth, color) { + this.gridWidth = gridWidth; + this.ySteps = ySteps; + } + + /// + /// Adds the overlay to a graph. + /// + public override void DrawOn(GraphRenderer target) { + base.DrawOn(target); + + int gap = target.Height / ySteps; + for (int y = 1; y < ySteps; y++) { + DrawRow(target, y * gap, gridWidth, color); + } + + float logStart = MathF.Log10(target.StartFrequency), + logEnd = MathF.Log10(target.EndFrequency); + for (int digit = (int)logStart, last = (int)logEnd; digit <= last; digit++) { + for (int value = 1; value < 10; value++) { + float freq = value * MathF.Pow(10, digit); + if (freq > target.StartFrequency && freq < target.EndFrequency) { + DrawColumn(target, (int)(target.Width * QMath.LerpInverse(logStart, logEnd, MathF.Log10(freq))), gridWidth, color); + } + } + } + } + } +} \ No newline at end of file