internal class Renderer:IDisposable
{
private CancellationTokenSource? tokenSource;
public object locker;
private int lastIndexDrawObj;
private SKBitmap? latestFrame;
private IEnumerator<Wrapper<Ball>>? enumeratorStreamDraw;
private IParticleTreeModel<Ball> particleTreeModel;
private SKPaint ballPaint;
private Camera2D coordMapper;
private bool disposedValue;
public Action DrawHandler { get; set; }
public SKBitmap LatestFrame => latestFrame;
public Renderer(IParticleTreeModel<Ball> particleTreeModel, Camera2D coordMapper)
{
ballPaint = new SKPaint() { IsStroke = false, IsAntialias = true };
locker = new object();
this.particleTreeModel = particleTreeModel;
this.coordMapper = coordMapper;
}
internal async Task<long> RenderLoop()
{
tokenSource?.Cancel();
tokenSource?.Dispose();
Stopwatch sw = Stopwatch.StartNew();
while (sw.ElapsedMilliseconds < 10_000)
{
tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var taskRender = Task.Run(() => RenderFrame(token, coordMapper.ViewportSize.X, coordMapper.ViewportSize.Y));
bool isComplected = await Task.WhenAny(taskRender, Task.Delay(50,token)) == taskRender;
lock (locker)
{
if (isComplected)
{
latestFrame = taskRender.Result;
break;
}
else
{
tokenSource.Cancel();
latestFrame = taskRender.Result;
}
}
}
DrawHandler?.Invoke(); // вызывает кучу редиректов до
// canvas.Dispatcher.Invoke(() => canvas.InvalidateVisual())
sw.Stop();
return sw.ElapsedMilliseconds;
}
private SKBitmap RenderFrame(CancellationToken token, float w, float h)
{
SKBitmap image;
lock (locker)
{
if (latestFrame != null && latestFrame.Width == (int)w && latestFrame.Height == (int)h)
{
image = latestFrame;
}
else
{
if (latestFrame == null)
image = new SKBitmap((int)w, (int)h);
else
{
latestFrame.Dispose();
image = new SKBitmap((int)w, (int)h);
}
enumeratorStreamDraw = null;
}
}
using var canvas = new SKCanvas(image);
drawParticleQuadTreePart(token, canvas, w, h);
return image;
}
private void drawParticleQuadTreePart(CancellationToken token, SKCanvas g, float w, float h)
{
if (enumeratorStreamDraw == null)
{
enumeratorStreamDraw = particleTreeModel.GetBallsIterator(); // Создаем новый итератор
}
while (enumeratorStreamDraw.MoveNext())
{
ref var o = ref enumeratorStreamDraw.Current.Data;
ballPaint.Color = o.color;
var pos = coordMapper.WorldToCanvas(o.Pos);
g.DrawCircle(pos, coordMapper.ToCanvas(o.radius), ballPaint);
if (token.IsCancellationRequested)
{
return;
}
}
enumeratorStreamDraw = null;
}
protected virtual void Dispose(bool disposing){}
}
}
/////////////// отрисовка
lock(renderer.locker)
if(renderer.LatestFrame!=null)
canvas.DrawBitmap(renderer.LatestFrame,0,0 );
Я же сам ответил, так же. Я не понимаю, каким образом элемент знает что он не изменится.
Почему событие MouseMove с 10 фпс происходит, для примера, просто отрисовка кружка по курсору, почему если сдвинуть мышку на 2 пикселя, не происходит даже вызова MouseMove, а если на 20 пикселей сдвинуть то произойдет (в версии где всего этого нету с drawingContext.DrawRectangle(Brushes.Transparent итд).
В чем механизм.