225 lines
6.8 KiB
C#
225 lines
6.8 KiB
C#
using System;
|
|
|
|
using Engine.Core;
|
|
|
|
using SDL3;
|
|
|
|
namespace Engine.Integration.SDL3;
|
|
|
|
public class Sdl3Window : Behaviour, IWindow, IDisposable, IEnterUniverse, IExitUniverse
|
|
{
|
|
public Event<IWindow, IWindow.StateChangedArguments> OnStateChanged { get; } = new();
|
|
public Event<IWindow, IWindow.FocusStateChangedArguments> OnFocusStateChanged { get; } = new();
|
|
public Event<IWindow, IWindow.ModeChangedArguments> OnModeChanged { get; } = new();
|
|
public Event<IWindow, IWindow.ShowStateChangedArguments> OnShowStateChanged { get; } = new();
|
|
public Event<IWindow, IWindow.ResizeModeChangedArguments> OnResizeModeChanged { get; } = new();
|
|
|
|
public Event<IWindow, IWindow.TitleChangedArguments> OnTitleChanged { get; } = new();
|
|
public Event<IWindow, IWindow.TargetFpsChangedArguments> OnTargetFpsChanged { get; } = new();
|
|
public Event<IWindow, IWindow.SizeChangedArguments> OnSizeChanged { get; } = new();
|
|
public Event<IWindow, IWindow.BackgroundColorChangedArguments> OnBackgroundColorChanged { get; } = new();
|
|
|
|
public IntPtr Window { get; private set; } = IntPtr.Zero;
|
|
|
|
public WindowState State
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
switch (value)
|
|
{
|
|
case WindowState.Open: OpenWindow(); break;
|
|
case WindowState.Closed: default: CloseWindow(); break;
|
|
}
|
|
|
|
WindowState previousState = field;
|
|
field = value;
|
|
OnStateChanged.Invoke(this, new(previousState));
|
|
}
|
|
} = WindowState.Open;
|
|
|
|
public WindowFocusState FocusState
|
|
{
|
|
get => field;
|
|
internal set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
WindowFocusState previousFocusState = field;
|
|
field = value;
|
|
OnFocusStateChanged.Invoke(this, new(previousFocusState));
|
|
}
|
|
} = WindowFocusState.Unfocused;
|
|
|
|
public WindowMode Mode
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
if (value is WindowMode.Windowed or WindowMode.BorderlessWindowed)
|
|
{
|
|
SDL.SetWindowFullscreen(Window, false);
|
|
SDL.SyncWindow(Window);
|
|
}
|
|
|
|
if (Window != IntPtr.Zero)
|
|
switch (value)
|
|
{
|
|
case WindowMode.Windowed: SDL.SetWindowBordered(Window, true); break;
|
|
case WindowMode.BorderlessWindowed: SDL.SetWindowBordered(Window, false); break;
|
|
case WindowMode.BorderlessFullscreen: SDL.SetWindowFullscreen(Window, true); break;
|
|
case WindowMode.Fullscreen: SDL.SetWindowFullscreen(Window, true); break;
|
|
}
|
|
|
|
SDL.SyncWindow(Window);
|
|
|
|
WindowMode previousMode = field;
|
|
field = value;
|
|
OnModeChanged.Invoke(this, new(previousMode));
|
|
}
|
|
} = WindowMode.Windowed;
|
|
|
|
public WindowShowState ShowState
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
if (Window != IntPtr.Zero)
|
|
switch (value)
|
|
{
|
|
case WindowShowState.Normal: SDL.RestoreWindow(Window); break;
|
|
case WindowShowState.Minimized: SDL.MinimizeWindow(Window); break;
|
|
case WindowShowState.Maximized: SDL.MaximizeWindow(Window); break;
|
|
}
|
|
|
|
WindowShowState previousShowState = field;
|
|
field = value;
|
|
OnShowStateChanged.Invoke(this, new(previousShowState));
|
|
}
|
|
} = WindowShowState.Normal;
|
|
|
|
public WindowResizeMode ResizeMode
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
if (Window != IntPtr.Zero)
|
|
switch (value)
|
|
{
|
|
case WindowResizeMode.Fixed:
|
|
SDL.SetWindowResizable(Window, false);
|
|
break;
|
|
case WindowResizeMode.Resizable:
|
|
case WindowResizeMode.AspectLocked:
|
|
SDL.SetWindowResizable(Window, true);
|
|
break;
|
|
}
|
|
|
|
WindowResizeMode previousResizeMode = field;
|
|
field = value;
|
|
OnResizeModeChanged.Invoke(this, new(previousResizeMode));
|
|
}
|
|
} = WindowResizeMode.Fixed;
|
|
|
|
public ColorRGB BackgroundColor
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
ColorRGB previousBackgroundColor = field;
|
|
field = value;
|
|
OnBackgroundColorChanged.Invoke(this, new(previousBackgroundColor));
|
|
}
|
|
} = new ColorRGB(35, 20, 35);
|
|
|
|
public string Title
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
string previousTitle = field;
|
|
field = value;
|
|
OnTitleChanged.Invoke(this, new(previousTitle));
|
|
}
|
|
} = nameof(Sdl3Window);
|
|
|
|
public Vector2DInt Size
|
|
{
|
|
get => field;
|
|
set
|
|
{
|
|
if (value == field)
|
|
return;
|
|
|
|
if (value.Max(Vector2DInt.One) == Vector2DInt.One)
|
|
throw new Exception($"Window size can not be smaller than 1x1");
|
|
|
|
Vector2DInt previousSize = field;
|
|
field = value;
|
|
OnSizeChanged.Invoke(this, new(previousSize));
|
|
}
|
|
} = Vector2DInt.Zero;
|
|
|
|
public void ExitUniverse(IUniverse universe) => CloseWindow();
|
|
public void EnterUniverse(IUniverse universe)
|
|
{
|
|
if (State == WindowState.Open)
|
|
OpenWindow();
|
|
}
|
|
|
|
private void OpenWindow()
|
|
{
|
|
if (!UniverseObject.IsInUniverse)
|
|
throw new Exception($"{UniverseObject.Name} is not in a universe. The window can not be opened.");
|
|
|
|
SDL.WindowFlags windowFlags = 0;
|
|
switch (Mode)
|
|
{
|
|
case WindowMode.Windowed: break;
|
|
case WindowMode.Fullscreen: windowFlags |= SDL.WindowFlags.Fullscreen; break;
|
|
case WindowMode.BorderlessWindowed: windowFlags |= SDL.WindowFlags.Borderless; break;
|
|
case WindowMode.BorderlessFullscreen: windowFlags |= SDL.WindowFlags.Fullscreen | SDL.WindowFlags.Borderless; break;
|
|
}
|
|
|
|
if (!SDL.Init(SDL.InitFlags.Video))
|
|
throw new Exception($"SDL_Init failed: {SDL.GetError()}");
|
|
|
|
Window = SDL.CreateWindow(Title, Size.X, Size.Y, windowFlags | SDL.WindowFlags.OpenGL);
|
|
if (Window == IntPtr.Zero)
|
|
throw new Exception($"SDL_CreateWindowAndRenderer failed: {SDL.GetError()}");
|
|
}
|
|
|
|
private void CloseWindow()
|
|
{
|
|
if (Window != IntPtr.Zero) SDL.DestroyWindow(Window);
|
|
|
|
Window = IntPtr.Zero;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
CloseWindow();
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|