using System.Numerics;
using AcDream.App.Rendering.Gpu;
namespace AcDream.App.UI;
/// Leaf widget for dat Type 0xD (UIElement_Viewport). Blits the texture produced by its
/// IUiViewportRenderer (run in the pre-UI hook) as a single sprite at its own rect. The 3-D render
/// does NOT happen here (OnDraw only has a 2-D context).
public sealed class UiViewport : UiElement
{
public override bool ConsumesDatChildren => true;
/// Optional click action. Non-null makes the viewport handle the press
/// itself instead of it being captured as a window move.
public System.Action? Clicked { get; set; }
/// Position-aware variant with viewport-local pixel coordinates.
public System.Action? ClickedAt { get; set; }
public override bool HandlesClick => Clicked is not null || ClickedAt is not null;
public override bool OnEvent(in UiEvent e)
{
if (Clicked is null && ClickedAt is null) return base.OnEvent(e);
switch (e.Type)
{
case UiEventType.MouseDown: return true; // consume the press; act on Click
case UiEventType.Click:
Clicked?.Invoke();
ClickedAt?.Invoke(e.Data1, e.Data2);
return true;
}
return base.OnEvent(e);
}
/// Renderer that produces the off-screen texture. Set by GameWindow wiring (later task).
public IUiViewportRenderer? Renderer { get; set; }
///
/// Campaign V slice V4a: the off-screen FBO colour texture produced by the
/// pre-UI hook, registered into the device's texture table by the
/// pre-approved paperdoll/appraisal transitional seam
/// (GlGpuDevice.RegisterExternalColorTexture, campaign doc §7.1) —
/// its owning renderer (PrivateEntityViewportRenderer) stays raw GL
/// until V4g. = nothing to blit.
/// internal, not public: is an internal type
/// (the pinned RHI contract); UiViewport stays public.
///
internal GpuTextureSlot TextureSlot { get; set; } = GpuTextureSlot.Unassigned;
protected override void OnDraw(UiRenderContext ctx)
{
if (!Visible || !TextureSlot.IsAssigned) return;
uint textureHandle = AcDream.App.Rendering.TextRenderer.ResolveExternalTextureSlot(TextureSlot);
if (textureHandle == 0) return;
// Local origin is already at this widget's Left/Top (PushTransform applied by DrawSelfAndChildren).
//
// V depends on the backend that produced the texture, and slice V6l is
// where that stopped being a constant. A GL off-screen FBO colour texture
// has a BOTTOM-LEFT origin while the UI sprite convention is top-left, so
// its V is flipped (v0=1, v1=0) — without that the doll renders
// upside-down, which is what the line this replaces had always said. A
// Vulkan render target has a top-left origin and needs no flip; applying
// one drew the doll on its head in the first Vulkan capture. The renderer
// that made the texture is the one that knows.
bool bottomUp = Renderer?.TextureIsBottomUp ?? true;
float v0 = bottomUp ? 1f : 0f;
float v1 = bottomUp ? 0f : 1f;
ctx.DrawSprite(textureHandle, 0f, 0f, Width, Height, 0f, v0, 1f, v1, Vector4.One);
}
}