feat(ui): debug overlay + refined input controls

Adds the first on-screen HUD for the dev client plus today's mouse-control
refinements. Also lands yesterday's scenery-alignment changes that were
left uncommitted in the working tree.

Overlay:
- BitmapFont rasterizes a system TTF via StbTrueTypeSharp into a 512x512
  R8 atlas at startup (Consolas on Windows, DejaVu/Menlo fallbacks)
- TextRenderer batches 2D quads in screen-space with ortho projection;
  one shader + two draw calls (rect then text) for panel backgrounds
  under glyphs
- DebugOverlay composes info / stats / compass / help panels on top of
  the 3D scene; toggles via F1/F4/F5/F6; transient toasts for key events
- DebugLineRenderer and its shaders (carried over from the scenery work)
  are properly committed in this commit

Controls:
- Per-mode mouse sensitivity (Chase 0.15, Fly 1.0, Orbit 1.0); F8/F9 to
  adjust the active mode multiplicatively (x1.2)
- Hold RMB to free-orbit the chase camera around the player; release
  stays at the new angle (no snap-back)
- Mouse-wheel zooms chase distance between 2m and 40m
- Chase pitch widened to [-0.7, 1.4] so mouse-Y tilts both ways from
  the default neutral angle

Scenery alignment (carried from yesterday's session):
- ShadowObjectRegistry AllEntriesForDebug + Scale field
- SceneryGenerator uses ACViewer's OnRoad polygon test + baseLoc +
  set_heading rotation
- BSPQuery dispatchers accept localToWorld so normals/offsets transform
  correctly per part
- TransitionTypes.CylinderCollision rewritten with wall-slide + push-out
- PhysicsDataCache caches visual-mesh AABB for scenery that lacks
  physics Setup bounds
This commit is contained in:
Erik 2026-04-17 18:45:38 +02:00
parent 6b4e7569a3
commit ff325abd7b
20 changed files with 2734 additions and 268 deletions

View file

@ -14,17 +14,34 @@ public sealed class ChaseCamera : ICamera
public float Aspect { get; set; } = 16f / 9f;
public float FovY { get; set; } = MathF.PI / 3f;
/// <summary>Distance behind the player.</summary>
/// <summary>Distance behind the player. Clamped to [<see cref="DistanceMin"/>, <see cref="DistanceMax"/>].</summary>
public float Distance { get; set; } = 8f;
public const float DistanceMin = 2f;
public const float DistanceMax = 40f;
/// <summary>Camera pitch above horizontal (radians). Positive = look down.</summary>
public float Pitch { get; set; } = 0.35f; // ~20 degrees
/// <summary>
/// Additional yaw applied on top of the player's heading when positioning
/// the camera. Used by the hold-RMB "inspect" mode to orbit around the
/// player without rotating the character. Snap to 0 to return the camera
/// to directly behind the player.
/// </summary>
public float YawOffset { get; set; } = 0f;
/// <summary>Vertical offset from the player's feet to the look-at point (eye height).</summary>
public float EyeHeight { get; set; } = 1.5f;
private const float PitchMin = 0.05f;
private const float PitchMax = 1.4f; // ~80 degrees
// Pitch range: negative values place the camera below the player's Z
// (at distance * sin(Pitch)) so the player can be viewed from a low
// angle. Clamped to -0.7 to avoid pushing the camera deep underground;
// at -0.7 and Distance=8 the camera is ~5m below player-Z which will
// clip terrain on hills but is OK on flat ground. 1.4 ≈ looking
// straight down. Wider than the old [0.05, 1.4] so mouse-Y moves the
// camera in both directions from the neutral [~20°] default.
private const float PitchMin = -0.7f;
private const float PitchMax = 1.4f;
private float _playerYaw;
private Vector3 _lookAt;
@ -43,9 +60,11 @@ public sealed class ChaseCamera : ICamera
_playerYaw = playerYaw;
_lookAt = playerPosition + new Vector3(0f, 0f, EyeHeight);
// Camera offset: behind the player (-forward direction) and above.
float forwardX = MathF.Cos(playerYaw);
float forwardY = MathF.Sin(playerYaw);
// Camera offset: behind the player (-forward direction) plus any
// YawOffset for the hold-RMB inspect orbit mode.
float effectiveYaw = playerYaw + YawOffset;
float forwardX = MathF.Cos(effectiveYaw);
float forwardY = MathF.Sin(effectiveYaw);
float horizontalDist = Distance * MathF.Cos(Pitch);
float verticalDist = Distance * MathF.Sin(Pitch);
@ -63,4 +82,12 @@ public sealed class ChaseCamera : ICamera
{
Pitch = Math.Clamp(Pitch + delta, PitchMin, PitchMax);
}
/// <summary>
/// Adjust distance (zoom) by a delta, clamped to [DistanceMin, DistanceMax].
/// </summary>
public void AdjustDistance(float delta)
{
Distance = Math.Clamp(Distance + delta, DistanceMin, DistanceMax);
}
}