refactor(input): own pointer and callback lifetime
Move camera pointer, framebuffer resize, and retained/devtools input edges behind focused reversible owners. Preserve input priority while making shutdown deactivate callbacks before live-session retirement and retry physical detach without stranding transport teardown.
This commit is contained in:
parent
d09e246d3a
commit
8b8afeefa3
42 changed files with 4029 additions and 461 deletions
118
src/AcDream.App/Rendering/FramebufferResizeController.cs
Normal file
118
src/AcDream.App/Rendering/FramebufferResizeController.cs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
using AcDream.App.Input;
|
||||
using Silk.NET.Maths;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
internal interface IFramebufferViewportTarget
|
||||
{
|
||||
void ResizeViewport(int width, int height);
|
||||
}
|
||||
|
||||
internal sealed class SilkFramebufferViewportTarget(GL gl)
|
||||
: IFramebufferViewportTarget
|
||||
{
|
||||
private readonly GL _gl = gl ?? throw new ArgumentNullException(nameof(gl));
|
||||
|
||||
public void ResizeViewport(int width, int height) =>
|
||||
_gl.Viewport(0, 0, (uint)width, (uint)height);
|
||||
}
|
||||
|
||||
internal interface IFramebufferCameraTarget
|
||||
{
|
||||
void SetAspect(float aspect);
|
||||
}
|
||||
|
||||
internal sealed class CameraFramebufferTarget(CameraController camera)
|
||||
: IFramebufferCameraTarget
|
||||
{
|
||||
private readonly CameraController _camera = camera
|
||||
?? throw new ArgumentNullException(nameof(camera));
|
||||
|
||||
public void SetAspect(float aspect) => _camera.SetAspect(aspect);
|
||||
}
|
||||
|
||||
internal interface IFramebufferDevToolsTarget
|
||||
{
|
||||
void ResetLayout(int width, int height);
|
||||
}
|
||||
|
||||
internal sealed class DevToolsFramebufferTarget(DevToolsFramePresenter presenter)
|
||||
: IFramebufferDevToolsTarget
|
||||
{
|
||||
private readonly DevToolsFramePresenter _presenter = presenter
|
||||
?? throw new ArgumentNullException(nameof(presenter));
|
||||
|
||||
public void ResetLayout(int width, int height) =>
|
||||
_presenter.ResetLayout(
|
||||
width,
|
||||
height,
|
||||
DevToolsPanelLayoutCondition.Always);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The one framebuffer-size target. Logical gameplay/UI dimensions continue
|
||||
/// to come from Window.Size; this owner only applies physical framebuffer
|
||||
/// viewport/aspect changes in the frozen acdream host order.
|
||||
/// </summary>
|
||||
internal sealed class FramebufferResizeController
|
||||
{
|
||||
private readonly ViewportAspectState _viewportAspect;
|
||||
private IFramebufferViewportTarget? _viewport;
|
||||
private IFramebufferCameraTarget? _camera;
|
||||
private IFramebufferDevToolsTarget? _devTools;
|
||||
|
||||
public FramebufferResizeController(ViewportAspectState viewportAspect) =>
|
||||
_viewportAspect = viewportAspect
|
||||
?? throw new ArgumentNullException(nameof(viewportAspect));
|
||||
|
||||
public void BindViewport(IFramebufferViewportTarget viewport)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(viewport);
|
||||
BindOnce(ref _viewport, viewport, "viewport");
|
||||
}
|
||||
|
||||
public void BindCamera(IFramebufferCameraTarget camera)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(camera);
|
||||
BindOnce(ref _camera, camera, "camera");
|
||||
}
|
||||
|
||||
public void BindDevTools(IFramebufferDevToolsTarget devTools)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(devTools);
|
||||
BindOnce(ref _devTools, devTools, "developer tools");
|
||||
}
|
||||
|
||||
public void UnbindDevTools(IFramebufferDevToolsTarget devTools)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(devTools);
|
||||
if (ReferenceEquals(_devTools, devTools))
|
||||
_devTools = null;
|
||||
}
|
||||
|
||||
public void Resize(Vector2D<int> newSize) => Resize(newSize.X, newSize.Y);
|
||||
|
||||
public void Resize(int width, int height)
|
||||
{
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
// Frozen order: GL viewport, shared aspect publication, camera, then
|
||||
// optional ImGui layout reset. Late binding never replays an earlier
|
||||
// resize transition.
|
||||
_viewport?.ResizeViewport(width, height);
|
||||
_viewportAspect.Update(width, height);
|
||||
_camera?.SetAspect(width / (float)height);
|
||||
_devTools?.ResetLayout(width, height);
|
||||
}
|
||||
|
||||
private static void BindOnce<T>(ref T? slot, T value, string name)
|
||||
where T : class
|
||||
{
|
||||
if (slot is not null && !ReferenceEquals(slot, value))
|
||||
throw new InvalidOperationException(
|
||||
$"The framebuffer {name} target is already bound.");
|
||||
slot = value;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue