using System.Threading.Tasks;
using IFSEngine.Model;
using IFSEngine.Rendering;
namespace IFSRenderer.AvaloniaShell.Rendering;
/// <summary>
/// The engine operations the UI performs from inside a queued render-thread action.
/// </summary>
/// <remarks>
/// <para>
/// This is deliberately the EXACT set of <see cref="RendererGL"/> members the windows reach
/// for — nothing more. Its only purpose is to let the UI be exercised without an OpenGL
/// context: <see cref="RendererGL"/> cannot be constructed without one, so any test that
/// touches an add/remove/parameter path would otherwise need a GPU and a window.
/// </para>
/// <para>
/// Keep it narrow. If a new call site needs another engine member, add it here consciously
/// rather than widening the interface to <see cref="RendererGL"/> itself — the narrowness is
/// what keeps the UI testable.
/// </para>
/// </remarks>
public interface IRenderer
{
/// <summary>Uploads a fractal's parameters, resizing buffers to match it.</summary>
void LoadParams(IFS ifs);
/// <summary>Marks the iterator/parameter GPU buffer dirty so it is re-uploaded.</summary>
void InvalidateParamsBuffer();
/// <summary>Discards the accumulated histogram, restarting the sample average.</summary>
void InvalidateHistogramBuffer();
/// <summary>
/// Marks the gradient buffer dirty so the palette is re-uploaded.
/// </summary>
/// <remarks>
/// The palette became its OWN GPU buffer when ColorPalette replaced FlamePalette, sampled
/// into a fixed-resolution gradient on upload. Invalidating the params buffer no longer
/// touches it, so a palette change without this leaves the render on the previous gradient.
/// </remarks>
void InvalidatePaletteBuffer();
/// <summary>Sets the histogram size as a fraction of the display resolution.</summary>
void SetHistogramScale(double scale);
/// <summary>Fits the histogram to the display at the engine's default 98%.</summary>
void SetHistogramScaleToDisplay();
/// <summary>Draws the focal plane while a focus control is being dragged.</summary>
bool MarkAreaInFocus { get; set; }
bool EnableDE { get; set; }
int DEMaxRadius { get; set; }
double DEPower { get; set; }
double DEThreshold { get; set; }
int MaxFilterRadius { get; set; }
bool EnablePerceptualUpdates { get; set; }
int TargetFramerate { get; set; }
int WorkgroupCount { get; }
Task SetWorkgroupCount(int count);
}
/// <summary>Passes <see cref="IRenderer"/> straight through to the real engine.</summary>
public sealed class RendererGLAdapter : IRenderer
{
private readonly RendererGL _renderer;
public RendererGLAdapter(RendererGL renderer) => _renderer = renderer;
public void LoadParams(IFS ifs) => _renderer.LoadParams(ifs);
public void InvalidateParamsBuffer() => _renderer.InvalidateParamsBuffer();
public void InvalidateHistogramBuffer() => _renderer.InvalidateHistogramBuffer();
public void InvalidatePaletteBuffer() => _renderer.InvalidatePaletteBuffer();
public void SetHistogramScale(double scale) => _renderer.SetHistogramScale(scale);
public void SetHistogramScaleToDisplay() => _renderer.SetHistogramScaleToDisplay();
public bool MarkAreaInFocus
{
get => _renderer.MarkAreaInFocus;
set => _renderer.MarkAreaInFocus = value;
}
public bool EnableDE
{
get => _renderer.EnableDE;
set => _renderer.EnableDE = value;
}
public int DEMaxRadius
{
get => _renderer.DEMaxRadius;
set => _renderer.DEMaxRadius = value;
}
public double DEPower
{
get => _renderer.DEPower;
set => _renderer.DEPower = value;
}
public double DEThreshold
{
get => _renderer.DEThreshold;
set => _renderer.DEThreshold = value;
}
public int MaxFilterRadius
{
get => _renderer.MaxFilterRadius;
set => _renderer.MaxFilterRadius = value;
}
public bool EnablePerceptualUpdates
{
get => _renderer.EnablePerceptualUpdates;
set => _renderer.EnablePerceptualUpdates = value;
}
public int TargetFramerate
{
get => _renderer.TargetFramerate;
set => _renderer.TargetFramerate = value;
}
public int WorkgroupCount => _renderer.WorkgroupCount;
public Task SetWorkgroupCount(int count) => _renderer.SetWorkgroupCount(count);
}