using AcDream.App.Rendering.Wb;
using AcDream.App.UI;
using AcDream.Core.Lighting;
using AcDream.Core.World;
namespace AcDream.App.Rendering;
///
/// CC6b-MOUNT: narrow seam mirroring IPaperdollDollRenderer so
/// 's rebuild/render logic can be
/// exercised with a fake in tests without a live GPU device.
///
internal interface IChargenPreviewRenderer
{
void SetPreview(WorldEntity? entity);
///
/// Sets or clears the environment backdrop entity drawn BEHIND the
/// preview (Campaign CC gate round 1 Batch D, GF-7/GF-14) — retail's
/// gmCG3DView::m_pbgObject. See
/// for the
/// decomp-cited placement.
///
void SetBackdrop(WorldEntity? entity);
uint Render(int width, int height);
}
///
/// Chargen-specific facade over the shared private creature viewport
/// () — CC6a's foundation half of
/// the campaign plan's "chargen preview renderer" deliverable. Mirrors
/// 's shape exactly, with a
/// heading-capable in place of the
/// paperdoll's fixed one.
///
///
/// NOT wired here (CC6b page-mount half, after CC4 merges per the
/// campaign's parallelism contract): mounting into the authored
/// Appearance/Summary viewport ids (0x100003bb / 0x10000406)
/// and binding the spin/color-wheel/rotate/zoom widgets to
/// //
/// . This class is a standalone,
/// composition-root-agnostic renderer — nothing in
/// AcDream.App/UI/Layout/ or RetailUiRuntime.cs references it
/// yet.
///
///
///
/// CC6b (pre-mount half): the preview now HAS a real live idle loop
/// (, retail's m_didAnimation DID
/// at 30fps via set_sequence_animation) instead of the CC6a-only held
/// rest pose — TS-83 is retired. still accepts a
/// static WorldEntity for callers that only want
/// ChargenPreviewEntityBuilder.TryBuild's unchanged rest-pose
/// snapshot; a caller that wants the animated preview constructs a
/// from
/// ChargenPreviewEntityBuilder.TryBuildAnimated and passes its
/// Entity here once — the animator mutates that SAME entity's
/// MeshRefs in place every Tick, and Render reads it
/// fresh (no re-SetPreview needed per frame; see
/// WorldEntity.MeshRefs's own "mutable so the animation tick can
/// replace it each frame" doc comment).
///
///
internal sealed class ChargenPreviewRenderer :
IUiViewportRenderer,
IChargenPreviewRenderer,
IDisposable
{
private readonly PrivateEntityViewportRenderer _renderer;
private readonly ChargenPreviewViewportCamera _camera;
internal ChargenPreviewRenderer(
IWorldPassScope scope,
AcDream.App.Rendering.Gpu.IGpuDevice device,
ICurrentGpuFrameSource frames,
WbDrawDispatcher dispatcher,
SceneLightingUboBinding lightUbo,
IEntityTextureLifetime textureLifetime,
IWbMeshAdapter meshAdapter,
uint heritageId = 0u,
ChargenPreviewCamera? camera = null,
// F16 (Campaign CC gate round 1 closeout): the Appearance and
// Summary pages each construct their OWN ChargenPreviewRenderer but
// share ONE process-wide TextureCache — see
// ChargenPreviewEntityBuilder.SummaryPreviewRenderId's own doc for
// the full collision trace. Defaulting to the Appearance page's
// pair keeps every pre-existing call site byte-identical; the
// composition root passes the Summary pair explicitly for its own
// instance.
uint renderId = ChargenPreviewEntityBuilder.PreviewRenderId,
uint backdropRenderId = ChargenPreviewEntityBuilder.PreviewBackdropRenderId)
{
// CC6b-MOUNT: when a caller supplies its own camera instance (the
// page-mount composition, which needs a SETTABLE camera for
// ChargenPreviewZoomController to tween — see
// ChargenPreviewController's own doc comment), wrap that exact
// instance instead of building a private, unreachable one.
_camera = camera is not null
? new ChargenPreviewViewportCamera(camera)
: new ChargenPreviewViewportCamera(heritageId);
_renderer = new PrivateEntityViewportRenderer(
scope,
device,
frames,
dispatcher,
lightUbo,
textureLifetime,
meshAdapter,
renderId,
_camera,
"chargen preview",
// Batch D (GF-7/GF-14): reserves the second draw-entity slot for
// the heritage's environment Setup — see PrivateEntityViewportRenderer's
// own doc comment on backdropRenderId.
backdropRenderId);
}
public bool TextureIsBottomUp => _renderer.TextureIsBottomUp;
///
/// Re-derives the fixed per-heritage camera eye
/// () — call whenever
/// the selected heritage changes, BEFORE the next .
///
public void SetHeritage(uint heritageId) => _camera.SetHeritage(heritageId);
public void SetPreview(WorldEntity? entity) => _renderer.SetEntity(entity);
public void SetBackdrop(WorldEntity? entity) => _renderer.SetBackdrop(entity);
public uint Render(int width, int height) => _renderer.Render(width, height);
public void Dispose() => _renderer.Dispose();
}