This commit is contained in:
2024-12-13 15:15:23 +03:00
parent 44bb459c1b
commit fa7b12c88c
66 changed files with 1732 additions and 389 deletions

View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Engine\Engine.csproj"/>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="src\App.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</ApplicationDefinition>
</ItemGroup>
<ItemGroup>
<Page Update="src\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,5 @@
<Application x:Class="PresenterWpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PresenterWpf">
</Application>

View File

@@ -0,0 +1,83 @@
using System.Configuration;
using System.Data;
using System.Windows;
using Engine.Graphics;
using Engine.Graphics.Texture;
using OpenTK.Windowing.Common;
namespace PresenterWpf;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
// Hijack the default startup event to start the engine
protected override void OnStartup(StartupEventArgs e)
{
var presenter = new PresenterWrapper();
var engine = new Engine.Engine(1, 1, _ => presenter);
// Since engine claims current thread for rendering, we need to create a new thread to run WPF
var thread = new Thread(() =>
{
var window = new MainWindow(engine);
presenter.Presenter = window;
window.Show();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
engine.Run();
// Shutdown WPF
Shutdown();
}
private class PresenterWrapper : IPresenter
{
private IPresenter? _presenter;
public IPresenter? Presenter
{
get => _presenter;
set
{
if (_presenter != null)
{
_presenter.Resize -= PresenterResize;
}
if (value != null)
{
value.Resize += PresenterResize;
}
_presenter = value;
}
}
public bool IsExiting => Presenter?.IsExiting ?? false;
public int Width => Presenter?.Width ?? 0;
public int Height => Presenter?.Height ?? 0;
public event Action<ResizeEventArgs>? Resize;
public void Present(IConstTexture parTexture)
{
Presenter?.Present(parTexture);
}
public void Update(double parDeltaTime)
{
Presenter?.Update(parDeltaTime);
}
private void PresenterResize(ResizeEventArgs e)
{
Resize?.Invoke(e);
}
}
}

View File

@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -0,0 +1,13 @@
<Window x:Class="PresenterWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PresenterWpf"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Closing="MainWindow_OnClosing">
<Grid>
<Image x:Name="Image" Width="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ActualHeight}" />
</Grid>
</Window>

View File

@@ -0,0 +1,101 @@
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Engine.Asset;
using Engine.Graphics;
using Engine.Graphics.Pixel;
using Engine.Graphics.Texture;
using OpenTK.Windowing.Common;
namespace PresenterWpf;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, IPresenter
{
public bool IsExiting { get; set; }
public int Width => (int)_cachedWidth;
public int Height => (int)_cachedHeight;
public event Action<ResizeEventArgs>? Resize;
private Engine.Engine _engine;
private Image<Rgb8>? _image;
private WriteableBitmap? _bitmap;
private int _cachedWidth;
private int _cachedHeight;
public MainWindow(Engine.Engine parEngine)
{
InitializeComponent();
_engine = parEngine;
}
public void Update(double parDeltaTime)
{
Dispatcher.Invoke(() =>
{
if ((int)Image.Width != _cachedWidth || (int)Image.Height != _cachedHeight)
{
_cachedWidth = (int)Image.Width;
_cachedHeight = (int)Image.Height;
}
});
// Resizes are lazy so resizing only happens when the window's size actually changes
if (Width != 0 && Height != 0)
_engine.Renderer.Resize(Width, Height);
}
public void Present(IConstTexture parTexture)
{
if (_image == null || parTexture.Width != _image.Width || parTexture.Height != _image.Height)
{
_image = new Image<Rgb8>(parTexture.Width, parTexture.Height);
}
parTexture.ReadPixels(_image);
Dispatcher.Invoke(() =>
{
if (_bitmap == null || _bitmap.PixelWidth != _image.Width || _bitmap.PixelHeight != _image.Height)
{
_bitmap = new WriteableBitmap(_image.Width, _image.Height, 96, 96, PixelFormats.Rgb24, null);
}
DrawImage(_image);
Image.Source = _bitmap;
});
}
private void DrawImage(Image<Rgb8> parImage)
{
try
{
_bitmap!.Lock();
_bitmap.WritePixels(new Int32Rect(0, 0, parImage.Width, parImage.Height), parImage.Pixels, parImage.Width * 3, 0,
0);
}
finally
{
_bitmap!.Unlock();
}
}
private void MainWindow_OnClosing(object? parSender, CancelEventArgs parE)
{
IsExiting = true;
}
}

View File

@@ -0,0 +1,5 @@
namespace PresenterWpf;
internal class Program
{
}