1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00
Artemis/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugViewModel.cs

147 lines
4.7 KiB
C#

using System;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Artemis.Core;
using Artemis.Core.Services;
using Ookii.Dialogs.Wpf;
using SkiaSharp;
using SkiaSharp.Views.WPF;
using Stylet;
namespace Artemis.UI.Screens.Settings.Debug.Tabs
{
public class RenderDebugViewModel : Screen
{
private readonly ICoreService _coreService;
private double _currentFps;
private ImageSource _currentFrame;
private int _renderWidth;
private int _renderHeight;
private string _frameTargetPath;
private string _renderer;
private int _frames;
private DateTime _frameCountStart;
public RenderDebugViewModel(ICoreService coreService)
{
DisplayName = "RENDERING";
_coreService = coreService;
}
public ImageSource CurrentFrame
{
get => _currentFrame;
set => SetAndNotify(ref _currentFrame, value);
}
public double CurrentFps
{
get => _currentFps;
set => SetAndNotify(ref _currentFps, value);
}
public int RenderWidth
{
get => _renderWidth;
set => SetAndNotify(ref _renderWidth, value);
}
public int RenderHeight
{
get => _renderHeight;
set => SetAndNotify(ref _renderHeight, value);
}
public string Renderer
{
get => _renderer;
set => SetAndNotify(ref _renderer, value);
}
public void SaveFrame()
{
VistaSaveFileDialog dialog = new VistaSaveFileDialog {Filter = "Portable network graphic (*.png)|*.png", Title = "Save render frame"};
dialog.FileName = $"Artemis frame {DateTime.Now:yyyy-dd-M--HH-mm-ss}.png";
bool? result = dialog.ShowDialog();
if (result == true)
{
if (dialog.FileName.EndsWith(".png"))
_frameTargetPath = dialog.FileName;
else
_frameTargetPath = dialog.FileName + ".png";
}
}
protected override void OnActivate()
{
_coreService.FrameRendered += CoreServiceOnFrameRendered;
_coreService.FrameRendering += CoreServiceOnFrameRendering;
base.OnActivate();
}
protected override void OnDeactivate()
{
_coreService.FrameRendered -= CoreServiceOnFrameRendered;
_coreService.FrameRendering -= CoreServiceOnFrameRendering;
base.OnDeactivate();
}
private void CoreServiceOnFrameRendered(object sender, FrameRenderedEventArgs e)
{
using SKImage skImage = e.Texture.Surface.Snapshot();
SKImageInfo bitmapInfo = e.Texture.ImageInfo;
if (_frameTargetPath != null)
{
using (SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100))
{
using (FileStream stream = File.OpenWrite(_frameTargetPath))
{
data.SaveTo(stream);
}
}
_frameTargetPath = null;
}
Execute.OnUIThreadSync(() =>
{
RenderHeight = bitmapInfo.Height;
RenderWidth = bitmapInfo.Width;
// ReSharper disable twice CompareOfFloatsByEqualityOperator
if (CurrentFrame is not WriteableBitmap writable || writable.Width != bitmapInfo.Width || writable.Height != bitmapInfo.Height)
{
CurrentFrame = e.Texture.Surface.Snapshot().ToWriteableBitmap();
return;
}
writable.Lock();
using (SKPixmap pixmap = new(bitmapInfo, writable.BackBuffer, writable.BackBufferStride))
{
// ReSharper disable once AccessToDisposedClosure - Looks fine
skImage.ReadPixels(pixmap, 0, 0);
}
writable.AddDirtyRect(new Int32Rect(0, 0, writable.PixelWidth, writable.PixelHeight));
writable.Unlock();
});
}
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
{
if (DateTime.Now - _frameCountStart >= TimeSpan.FromSeconds(1))
{
CurrentFps = _frames;
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
_frames = 0;
_frameCountStart = DateTime.Now;
}
_frames++;
}
}
}