using AcDream.App.Input;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Gpu;
using AcDream.App.Rendering.Gpu.Vk;
using AcDream.UI.Abstractions.Input;
using Silk.NET.Input;
namespace AcDream.App.Composition;
///
/// Campaign V slice V6h: the Vulkan arm of the host phase — now the only arm,
/// the raw-GL RetailHostInputCameraCompositionFactory it used to fork
/// from having been deleted at slice V11. Input, camera and pointer
/// construction are inlined directly rather than delegated, since there is no
/// longer a second implementation to share them with.
///
/// What is absent, and why. There is no GL fence ring: the RHI
/// device owns its own frames-in-flight through a timeline semaphore, so
/// retirement and slot indexing come from the device instead. There is no
/// : it was a raw-GL state tripwire, and
/// Vulkan has no global state for it to watch. Both nulls are read by the
/// phases that would otherwise consume them.
///
internal sealed class VulkanHostInputCameraCompositionFactory
: IHostInputCameraCompositionFactory
{
public IFramebufferViewportTarget CreateViewportTarget(
GameWindowGraphics graphics) =>
// The viewport is a pipeline dynamic state on Vulkan, set per pass by
// the encoder from the pass extent, so there is no persistent viewport
// to bind here. The framebuffer-resize controller still drives the
// camera aspect through its own target.
NullFramebufferViewportTarget.Instance;
public GpuFrameFlightController? CreateGpuFrameFlights(
GameWindowGraphics graphics) => null;
public IGpuDevice CreateGpuDevice(
GameWindowGraphics graphics,
GpuFrameFlightController? frameFlights) =>
RequireContext(graphics).Device;
public IGpuResourceRetirementQueue CreateRetirement(
GameWindowGraphics graphics,
GpuFrameFlightController? frameFlights,
IGpuDevice device) => device.Retirement;
public IRenderFrameSlotSource CreateFrameSlots(
GameWindowGraphics graphics,
GpuFrameFlightController? frameFlights,
IGpuDevice device) =>
new VulkanRenderFrameSlotSource(RequireContext(graphics).Device);
public WorldRenderDiagnostics? CreateWorldRenderDiagnostics(
GameWindowGraphics graphics,
IRenderFrameDiagnosticLog log) => null;
public SilkKeyboardSource CreateKeyboardSource(
IKeyboard keyboard,
HostQuiescenceGate quiescence) =>
SilkKeyboardSource.CreateDetached(keyboard, quiescence);
public SilkMouseSource CreateMouseSource(
IMouse mouse,
IInputCaptureSource capture,
IKeyboardSource? keyboard,
HostQuiescenceGate quiescence) =>
SilkMouseSource.CreateDetached(mouse, capture, keyboard, quiescence);
public IMouseLookCursor CreateMouseLookCursor(IMouse mouse) =>
new SilkMouseLookCursor(mouse);
public InputDispatcher CreateInputDispatcher(
IKeyboardSource keyboard,
IMouseSource mouse,
KeyBindings bindings) =>
InputDispatcher.CreateDetached(keyboard, mouse, bindings);
public CameraController CreateCameraController() =>
new(new OrbitCamera(), new FlyCamera());
public IFramebufferCameraTarget CreateCameraTarget(CameraController camera) =>
new CameraFramebufferTarget(camera);
public CameraPointerInputController CreateCameraPointerInput(
IReadOnlyList mice,
HostQuiescenceGate quiescence,
IInputCaptureSource capture,
LocalPlayerModeState playerMode,
CameraController camera,
ChaseCameraInputState chase,
IMouseSource mouse,
PointerPositionState pointer) =>
CameraPointerInputController.Create(
mice,
quiescence,
capture,
playerMode,
camera,
chase,
mouse,
pointer,
new EnvironmentInputMonotonicClock());
private static VulkanGraphicsContext RequireContext(
GameWindowGraphics graphics) =>
graphics.Vulkan
?? throw new InvalidOperationException(
"The Vulkan host factory was composed against a backend with no " +
"Vulkan context.");
///
/// Vulkan sets the viewport per pass from the pass extent, so there is no
/// persistent viewport binding for the resize controller to update. Size is
/// still recorded, because the swapchain recreation the host performs is
/// what actually resizes the surface.
///
private sealed class NullFramebufferViewportTarget : IFramebufferViewportTarget
{
public static NullFramebufferViewportTarget Instance { get; } = new();
private NullFramebufferViewportTarget()
{
}
public void ResizeViewport(int width, int height)
{
}
}
///
/// The flight slot per-frame buffers index by. Identical in role to the GL
/// ring's ; the count comes
/// from the device's timeline flight controller rather than a fence array.
///
private sealed class VulkanRenderFrameSlotSource(VulkanGpuDevice device)
: IRenderFrameSlotSource
{
public int CurrentSlot => device.Flights.CurrentSlot;
}
}