fix(D.2b): Slice 2 visual gate — frame the whole doll + caption the Slots toggle

Visual gate 1 (user): the doll rendered but only the legs showed (camera
aimed at the model origin = the feet) and the Slots button was invisible.

- DollCamera: aim the look-at at mid-body (~0.95 m) and stand back ~3.7 m
  so the whole ~1.9 m figure fits. (Size is a later retail-comparison
  polish per the user.)
- PaperdollController: the Slots button (0x100005BE) is found + wired
  (diagnostic confirmed armorSlots=9/9, viewport=UiViewport,
  slotsButton=UiButton) but its dat element has no face sprite, so it drew
  nothing. Give it a gold "Slots" caption (UiButton.Label, like chat Send)
  via a new datFont param on Bind. Temporary [Slice2-paperdoll] diagnostic
  logs the button rect + the found widgets (stripped at wrap-up).

Idle animation deferred to a focused follow-up (faithful idle needs a full
AnimatedEntity + Sequencer through the TickAnimations multi-branch path +
re-dress coordination — real integration risk vs the verified static doll).

Build + full App suite green (594).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-23 09:58:22 +02:00
parent 8b0365e7a9
commit fe319bd2aa
4 changed files with 41 additions and 14 deletions

View file

@ -3,21 +3,26 @@ using System.Numerics;
namespace AcDream.App.Rendering;
/// <summary>
/// Fixed camera for the paperdoll mini-scene. Eye and look-at from
/// <c>gmPaperDollUI::PostInit</c> (decomp lines 175521175527):
/// eye (0.12, -2.4, 0.88) looking at the origin, AC up-axis = +Z.
/// Fixed camera for the paperdoll mini-scene. Derived from <c>gmPaperDollUI::PostInit</c>
/// (decomp lines 175521175527: eye offset ~(0.12, -2.4, 0.88) about the origin), but with the
/// look-at raised to mid-body and the camera pulled back after the first visual gate: the doll's
/// model origin is at the FEET (z=0), so aiming at the origin framed only the lower legs. We aim
/// at ~0.95 m (a human's vertical centre) and stand back ~3.7 m so the whole ~1.9 m figure fits.
/// AC up-axis = +Z.
///
/// Uses the same <see cref="Matrix4x4.CreateLookAt"/> /
/// <see cref="Matrix4x4.CreatePerspectiveFieldOfView"/> convention as
/// <see cref="ChaseCamera"/> so the doll's triangle winding and back-face
/// culling match the world render pass.
///
/// Per-race camera distance (<c>UpdateForRace</c>) is deferred polish.
/// Exact per-race camera framing (<c>UpdateForRace</c>) is deferred polish.
/// </summary>
public sealed class DollCamera : ICamera
{
private static readonly Vector3 Eye = new(0.12f, -2.4f, 0.88f);
private static readonly Vector3 Target = Vector3.Zero;
// Body centre height (metres) the camera aims at — model origin is at the feet (z=0).
private const float BodyCentreZ = 0.95f;
private static readonly Vector3 Eye = new(0.12f, -3.7f, BodyCentreZ);
private static readonly Vector3 Target = new(0f, 0f, BodyCentreZ);
private static readonly Vector3 Up = Vector3.UnitZ; // AC up-axis = +Z, same as ChaseCamera
/// <summary>Vertical field of view in radians. ~34° default; tune at the visual gate.</summary>

View file

@ -2261,7 +2261,8 @@ public sealed class GameWindow : IDisposable
sendWield: (item, mask) => _liveSession?.SendGetAndWieldItem(item, mask),
// Empty equip slots show a visible frame (same square as the inventory grid) so every
// slot position is seen + usable; the live 3D character (the doll) is Slice 2.
emptySlotSprite: contentsEmpty);
emptySlotSprite: contentsEmpty,
datFont: vitalsDatFont); // Slice 2: caption the "Slots" toggle button
// Slice 2: capture the doll viewport widget (Type 0xD, element 0x100001D5) + the inventory
// frame so the per-frame pre-UI hook can render the 3-D doll into the widget's texture only