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(); }