Commit graph

561 commits

Author SHA1 Message Date
Kelsi
70abb12398 physics: send MSG_MOVE_JUMP on knockback to set FALLING flag correctly
applyKnockBack() sets grounded=false and applies vertical velocity, but
the normal jump detection path (nowJump && !wasJumping && grounded) never
fires during a server-driven knockback because no jump key is pressed.

Without MSG_MOVE_JUMP the game_handler never sets MovementFlags::FALLING
in movementInfo.flags, so all subsequent heartbeat packets carry incorrect
flags — the server sees the player as grounded while airborne.

Fix: fire movementCallback(MSG_MOVE_JUMP) directly from applyKnockBack()
so the FALLING flag is set immediately. MSG_MOVE_FALL_LAND is already sent
when grounded becomes true again (the existing wasFalling && grounded path).
2026-03-10 12:30:13 -07:00
Kelsi
c622fde7be physics: implement knockback simulation from SMSG_MOVE_KNOCK_BACK
Previously the handler ACKed with current position and ignored the
velocity fields entirely (vcos/vsin/hspeed/vspeed were [[maybe_unused]]).
The server expects the client to fly through the air on knockback — without
simulation the player stays in place while the server models them as airborne,
causing position desync and rubberbanding.

Changes:
- CameraController: add applyKnockBack(vcos, vsin, hspeed, vspeed)
  that sets knockbackHorizVel_ and launches verticalVelocity = -vspeed
  (server sends vspeed as negative for upward launches, matching TrinityCore)
- Physics loop: each tick adds knockbackHorizVel_ to targetPos then applies
  exponential drag (KNOCKBACK_HORIZ_DRAG=4.5/s) until velocity < 0.05 u/s
- GameHandler: parse all four fields, add KnockBackCallback, call it for
  the local player so the camera controller receives the impulse
- Application: register the callback — routes server knockback to physics

The existing ACK path is unchanged; the server gets position confirmation
as before while the client now actually simulates the trajectory.
2026-03-10 12:28:11 -07:00
Kelsi
1180f0227c rendering: fix WMO portal AABB transform for rotated WMOs
isPortalVisible() was computing the world-space AABB by directly
transforming pMin/pMax with the model matrix. This is incorrect for
rotated WMOs — when the model matrix includes rotations, components can
be swapped or negated, yielding an inverted AABB (worldMin.x >
worldMax.x) that causes frustum.intersectsAABB() to fail.

Fix: transform all 8 corners of the portal bounding box and take the
component-wise min/max, which gives the correct world-space AABB for any
rotation/scale. This was the root cause of portals being incorrectly
culled in rotated WMO instances (e.g. many dungeon and city WMOs).

Also squash the earlier spline-speed no-op fix (parse guid + float
instead of consuming the full packet for SMSG_SPLINE_SET_FLIGHT_SPEED
and friends) into this commit.
2026-03-10 11:51:43 -07:00
Kelsi
137b25f318 rendering: fix NPC movement animation IDs and remove redundant player anim
The renderer's CharAnimState machine already drives player character
animations (Run=5, Walk=4, Jump, Swim, etc.) — remove the conflicting
camera controller code added in the previous commit.

Fix creature movement animations to use the correct WoW M2 IDs:
4=Walk, 5=Run. Both the per-frame sync loop and the SMSG_MONSTER_MOVE
spline callback now use Run (5) for NPC movement.
2026-03-10 10:19:13 -07:00
Kelsi
279c30367a rendering: use Walk (anim 5) vs Run (anim 4) based on movement pace
CameraController now plays Walk (5) for backpedal/slow pace and Run (4)
for forward running (runPace), matching WoW's animation convention.
Also handles transitions between Walk and Run while already moving.
2026-03-10 10:10:46 -07:00
Kelsi
4e137c4061 rendering: drive Run/Stand animations from actual movement state
CameraController now transitions the player character to Run (anim 4)
on movement start and back to Stand (anim 0) on stop, guarded by a
prevPlayerMoving_ flag so animation time is not reset every frame.
Death animation (anim 1) is never overridden.

Application creature sync similarly switches creature models to Run (4)
when they move between server positions and Stand (0) when they stop,
with per-guid creatureWasMoving_ tracking to avoid per-frame resets.
2026-03-10 10:06:56 -07:00
Kelsi
c8d9d6b792 rendering/game: make player model semi-transparent in ghost form
Add GhostStateCallback to GameHandler, fired when PLAYER_FLAGS_GHOST
transitions on or off in UPDATE_OBJECT / login detection. Add
setInstanceOpacity() to CharacterRenderer to directly set opacity
without disturbing fade-in state. Application wires the callback to
set opacity 0.5 on ghost entry and 1.0 on resurrect.
2026-03-10 09:57:24 -07:00
Kelsi
c20d7c2638 rendering: return to Stand after one-shot emote animations complete
When a non-looping animation (e.g. wave, cheer, laugh emote) reaches
its end, transition back to Stand (animation 0) rather than freezing
on the last frame. Death (animation 1) is excluded — it stays on the
final frame as expected.

Fixes NPCs and players getting stuck in emote poses after SMSG_EMOTE.
2026-03-10 09:36:58 -07:00
Kelsi
60b93cdfd9 rendering/game: remove leftover debug dump I/O from hot paths
Remove active file-I/O debug block in character_renderer.cpp that
wrote composite textures as raw binary files to /tmp on every texture
composite generation. Remove the now-unused <fstream> include.

Remove the 10-shot hex dump of decompressed SMSG_MONSTER_MOVE payloads
in game_handler.cpp (dumpCount static); format has been confirmed.
2026-03-10 09:30:59 -07:00
Kelsi
b2dccca58c rendering: re-enable WMO camera collision with asymmetric smoothing
Previously disabled because the per-frame raycast caused erratic zoom
snapping at doorway transitions.  Re-enable using an asymmetrically-
smoothed collision limit: pull-in reacts quickly (τ≈60 ms) to prevent
the camera from ever visibly clipping through walls, while recovery is
slow (τ≈400 ms) so walking through a doorway zooms back out gradually
instead of snapping.

Uses wmoRenderer->raycastBoundingBoxes() which already has strict wall
filters (|normal.z|<0.20, surface-alignment check, ±0.9 height band)
to ignore floors, ramps, and arch geometry.
2026-03-10 09:13:31 -07:00
Kelsi
ea9c7e68e7 rendering,ui: sync selection circle to renderer instance position
The selection circle was positioned using the entity's game-logic
interpolator (entity->getX/Y/Z), while the actual M2 model is
positioned by CharacterRenderer's independent interpolator (moveInstanceTo).
These two systems can drift apart during movement, causing the circle
to appear under the wrong position relative to the visible model.

Fix: add CharacterRenderer::getInstancePosition / Application::getRenderPositionForGuid
and use the renderer's inst.position for XY (with footZ override for Z)
so the circle always tracks the rendered model exactly. Falls back to
the entity game-logic position when no CharacterRenderer instance exists.
2026-03-10 06:33:44 -07:00
Kelsi
5c830216be Remove debug LOG_INFO spam from applyEquipment; use DBC layout for texture fields
The verbose diagnostic logs added in 16cdde8 for Classic equipment debugging
are no longer needed now that the CSV string-detection bug is fixed. Remove
them to eliminate log spam on every character screen open.

Also replace the hardcoded `14 + region` texture field lookup with the same
DBC-layout-aware array pattern used in game_screen.cpp::updateCharacterTextures,
so texture field indices are correctly resolved per expansion.
2026-03-10 04:16:27 -07:00
Kelsi
16cdde82b3 rendering: add diagnostic logging to applyEquipment for Classic equipment debugging
Log each equipment item's displayModel, inventoryType, and DBC lookup result
to help identify why Classic character equipment does not render correctly.
Also log ItemDisplayInfo.dbc field count, found texture names per region,
and missing texture paths so the exact failure point is visible in logs.
2026-03-10 02:23:54 -07:00
Kelsi
6951b7803d game: fix SMSG_SPELL_GO miss-entry consumption in WotLK and TBC parsers
Both SpellGoParser::parse (WotLK) and TbcPacketParsers::parseSpellGo
(TBC) read missCount but did not consume the per-miss (guid + missType)
entries that follow, leaving unread bytes in the packet and silently
corrupting any subsequent parsing of cast-flags–gated spell data.

- Add SpellGoMissEntry{targetGuid, missType} and missTargets vector
  to SpellGoData
- WotLK parser now reads packed GUIDs + missType per miss entry
- TBC parser now reads full uint64 GUIDs + missType per miss entry
  (9 bytes per entry, bounds-checked)
- handleSpellGo now shows MISS/DODGE/PARRY/BLOCK combat text
  for each missed target when the local player cast the spell,
  complementing the existing SMSG_SPELLLOGMISS path
- Remove unused foliageLikeModel variable in m2_renderer pass-2 loop
  (fix unused-variable warning)
- Update smoke model comment in m2_renderer to reflect current state
2026-03-09 23:00:21 -07:00
Kelsi
edd7e5e591 Fix shadow flashing: per-frame shadow depth images and framebuffers
Single shadow depth image shared across MAX_FRAMES=2 in-flight GPU frames
caused a race: frame N's main pass reads shadow map while frame N+1's
shadow pass clears and writes it, producing visible flashing standing
still and while moving.

Fix: give each in-flight frame its own VkImage, VmaAllocation, VkImageView,
and VkFramebuffer for the shadow depth attachment. renderShadowPass() now
indexes all shadow resources by getCurrentFrame(), and layout transitions
track per-frame state in shadowDepthLayout_[frame]. Cleanup loops over
MAX_FRAMES=2. Descriptor sets already written per-frame; updated shadow
image view binding to use the matching per-frame view.
2026-03-09 22:14:32 -07:00
Kelsi
4d1be18c18 wmo: apply MOHD ambient color to interior group lighting
Read the ambient color from the MOHD chunk (BGRA uint32) and store it
on WMOModel as a normalized RGB vec3.  Pass it through ModelData into
the per-batch WMOMaterialUBO (replacing the unused pad[3] bytes, keeping
the struct at 64 bytes).  The GLSL interior branch now floors vertex
colors against the WMO ambient instead of a hardcoded 0.5, so dungeon
interiors respect the artist-specified ambient tint from the WMO root
rather than always clamping to grey.
2026-03-09 21:27:01 -07:00
Kelsi
e0d47040d3 Fix main-thread hang from terrain finalization; two-pass M2 rendering; tile streaming improvements
Hang/GPU device lost fix:
- M2_INSTANCES and WMO_INSTANCES finalization phases now create instances
  incrementally (32 per step / 4 per step) instead of all at once, eliminating
  the >1s main-thread stalls that caused GPU fence timeouts and device loss

M2 two-pass transparent rendering:
- Opaque/alpha-test batches render in pass 1, transparent/additive in pass 2
  (back-to-front sorted) to fix wing transparency showing terrain instead of
  trees — adds hasTransparentBatches flag to skip models with no transparency

Tile streaming improvements:
- Sort new load queue entries nearest-first so critical tiles load before
  distant ones during fast taxi flight
- Increase taxi load radius 6→8 tiles, unload 9→12 for better coverage

Water refraction gated on FSR:
- Disable water refraction when FSR is not active (bugged without upscaling)
- Auto-disable refraction if FSR is turned off while refraction was on
2026-03-09 20:58:49 -07:00
Kelsi
3eded6772d Implement bird/cricket ambient sounds and remove stale renderer TODO
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
- Add birdSounds_ and cricketSounds_ AmbientSample vectors to
  AmbientSoundManager, loaded from WoW MPQ paths:
  BirdAmbience/BirdChirp01-06.wav (up to 6 variants, daytime) and
  Insect/InsectMorning.wav + InsectNight.wav (nighttime). Missing files
  are silently skipped so the game runs without an MPQ too.
- updatePeriodicSounds() now plays a randomly chosen loaded variant
  at the scheduled interval instead of the previous no-op placeholder.
- Remove stale "TODO Phase 6: Vulkan underwater overlay" comment from
  Renderer::initialize(); the feature has been fully implemented in
  renderOverlay() / the swim effects pipeline since that comment was
  written.
2026-03-09 19:00:42 -07:00
Kelsi
6cba3f5c95 Implement SMSG_MULTIPLE_PACKETS unpacking and fix unused variable warning
- Parse bundled sub-packets from SMSG_MULTIPLE_PACKETS using the WotLK
  standard wire format (uint16_be size + uint16_le opcode + payload),
  dispatching each through handlePacket() instead of silently discarding.
  Rate-limited warning for malformed sub-packet overruns.
- Remove unused cullRadiusSq variable in TerrainRenderer::renderShadow()
  that produced a -Wunused-variable warning.
2026-03-09 18:52:34 -07:00
Kelsi
6a681bcf67 Implement terrain shadow casting in shadow depth pass
Add initializeShadow() to TerrainRenderer that creates a depth-only
shadow pipeline reusing the existing shadow.vert/frag shaders (same
path as WMO/M2/character renderers). renderShadow() draws all terrain
chunks with sphere culling against the shadow coverage radius. Wire
both init and draw calls into Renderer so terrain now casts shadows
alongside buildings and NPCs.
2026-03-09 18:34:27 -07:00
Kelsi
caea24f6ea Fix animated M2 flicker: free bone descriptor sets on instance removal
The boneDescPool_ had MAX_BONE_SETS=2048 but sets were never freed when
instances were removed (only when clear() reset the whole pool on map load).
As tiles streamed in/out, each new animated instance consumed 2 pool slots
(one per frame index) permanently. After ~1024 animated instances created
total, vkAllocateDescriptorSets began failing silently and returning
VK_NULL_HANDLE. render() skips instances with null boneSet[frameIndex],
making them invisible — appearing as per-frame flicker as the culling pass
included them but the render pass excluded them.

Fix: destroyInstanceBones() now calls vkFreeDescriptorSets() for each
non-null boneSet before destroying the bone SSBO. The pool already had
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT set for this purpose.
Also increased MAX_BONE_SETS from 2048 to 8192 for extra headroom.
2026-03-09 18:09:33 -07:00
Kelsi
68bf3d32b0 Wire ambient sound zone detection: setZoneType/setCityType was never called
Add AmbientSoundManager::setZoneId() that maps WoW zone IDs to the
appropriate ZoneType (forest/grasslands/desert/jungle/marsh/beach) or
CityType (Stormwind/Ironforge/Darnassus/Orgrimmar/Undercity/ThunderBluff)
and delegates to setZoneType/setCityType. Call it from the renderer's
zone transition handler so zone ambience (looping sounds, city bells,
etc.) actually activates when the player enters a zone.
2026-03-09 16:24:12 -07:00
Kelsi
6583ce9c57 Use server zone ID (SMSG_INIT_WORLD_STATES) for zone music selection
In online mode, SMSG_INIT_WORLD_STATES delivers the server-authoritative
zone ID when entering a new area. Prefer this over the tile-based fallback
so music transitions are accurate for small zones (city districts, caves,
dungeon entrances) that don't align with 533-unit tile boundaries.
2026-03-09 16:19:38 -07:00
Kelsi
a654dd5e99 Ensure zone music DBC enrichment runs at world load time
Call enrichFromDBC() again when loadOnlineWorld() sets cachedAssetManager,
so enrichment is guaranteed even when the asset manager was null at renderer
construction. enrichFromDBC() is idempotent (skips duplicate paths).
2026-03-09 16:18:08 -07:00
Kelsi
55082a0925 Remove unused baseZ/hasHeights variables in WaterRenderer::loadFromWMO
These were declared to handle per-vertex WMO liquid height variation but
never actually used below — the surface is built with a flat adjustedZ
height throughout. Remove to eliminate -Wunused-variable warnings.
2026-03-09 16:09:44 -07:00
Kelsi
b23cf06f1c Remove dead legacy GL Texture class
texture.hpp / texture.cpp implemented an unfinished OpenGL texture loader
(loadFromFile was a TODO stub) that had no callers — the project's texture
loading is entirely handled by VkTexture (vk_texture.hpp/cpp) after the
Vulkan migration. Remove both files and their CMakeLists entries.
2026-03-09 16:07:08 -07:00
Kelsi
43b9ecd857 Enrich zone music from AreaTable/ZoneMusic/SoundEntries DBC chain
Add ZoneManager::enrichFromDBC() which walks AreaTable.dbc (field 8 = ZoneMusicId)
→ ZoneMusic.dbc (fields 6/7 = day/night SoundEntryIds) → SoundEntries.dbc
(fields 3-12 = files, field 23 = DirectoryBase) and appends MPQ music paths for
all zones in the DBC, covering ~2300+ areas vs the previous ~15 hardcoded entries.

Existing hardcoded paths are preserved as the primary pool; DBC paths are added
only if not already present. Called from Renderer::init() after initialize().
2026-03-09 16:04:52 -07:00
Kelsi
bae32c1823 Add FSR3 Generic API path and harden runtime diagnostics
- AmdFsr3Runtime now probes both the legacy ffxFsr3* API and the newer
  generic ffxCreateContext/ffxDispatch API; selects whichever the loaded
  runtime library exports (GenericApi takes priority fallback)
- Generic API path implements full upscale + frame-generation context
  creation, configure, dispatch, and destroy lifecycle
- dlopen error captured and surfaced in lastError_ on Linux so runtime
  initialization failures are actionable
- FSR3 runtime init failure log now includes path kind, error string,
  and loaded library path for easier debugging
- tools/generate_ffx_sdk_vk_permutations.sh added: auto-bootstraps
  missing VK permutation headers; DXC auto-downloaded on Linux/Windows
  MSYS2; macOS reads from PATH (CI installs via brew dxc)
- CMakeLists: add upscalers/include to probe include dirs, invoke
  permutation script before SDK build, scope FFX pragma/ODR warning
  suppressions to affected TUs, add runtime-copy dependency on wowee
- UI labels updated from "FSR2" → "FSR3" in settings, tuning panel,
  performance HUD, and combo boxes
- CI macOS job now installs dxc via Homebrew for permutation codegen
2026-03-09 12:51:59 -07:00
Kelsi
ae48e4d7a6 Make FSR3 SDK integration Kits-only and align CI/docs
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
2026-03-09 05:00:51 -07:00
Kelsi
e916ef9bda Fix Windows frustum enum macro collision 2026-03-09 04:41:04 -07:00
Kelsi
1c7b87ee78 Remove FSR3 wrapper path and keep official Path-A runtime only 2026-03-09 04:33:05 -07:00
Kelsi
9ff9f2f1f1 Fix cross-platform FSR3 compile path and Path-A runtime wiring 2026-03-09 04:24:24 -07:00
Kelsi
78fa10c6ba Gate bridge interop export by wrapper capability bits
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
2026-03-09 02:45:37 -07:00
Kelsi
a08260e2b8 Add runtime wrapper ABI smoke probe and CI execution 2026-03-09 02:42:07 -07:00
Kelsi
ae3f2a53cf Enforce Linux bridge preflight during auto-fallback 2026-03-09 02:37:03 -07:00
Kelsi
3392e7b1a9 Enable Linux auto-fallback to dx12_bridge backend 2026-03-09 02:36:03 -07:00
Kelsi
27261303d2 Only export bridge interop handles for dx12_bridge backend 2026-03-09 02:35:02 -07:00
Kelsi
91f83cb108 Add Linux bridge preflight and FD-handle validation 2026-03-09 02:33:18 -07:00
Kelsi
faec3f6ec2 Enable Linux bridge mode and Vulkan FD interop exports 2026-03-09 02:28:49 -07:00
Kelsi
a2c6ce8a7b Log selected FSR3 runtime library and readiness 2026-03-09 02:20:14 -07:00
Kelsi
40289c5f8e Add wrapper capability query and runtime capability gating 2026-03-09 02:19:11 -07:00
Kelsi
45c2ed7a64 Expose wrapper backend mode in runtime diagnostics 2026-03-09 02:15:55 -07:00
Kelsi
ea2d452f4b Validate wrapper dispatch sizes and formats early 2026-03-09 02:13:16 -07:00
Kelsi
a0749df85e Make wrapper framegen transfer function HDR-aware 2026-03-09 02:10:55 -07:00
Kelsi
76728612ff Fix wrapper init error-path use-after-free 2026-03-09 02:10:01 -07:00
Kelsi
3e5f6d0084 Auto-fallback wrapper backend to DX12 bridge on Windows 2026-03-09 02:08:26 -07:00
Kelsi
1bcc2c6b85 Use monotonic interop fence values for FSR3 bridge dispatch 2026-03-09 02:03:03 -07:00
Kelsi
1c7908f02d Add ABI v3 fence-value sync for DX12 bridge dispatch 2026-03-09 01:58:45 -07:00
Kelsi
2bd9575419 Harden DX12 bridge dispatch cleanup and execution error handling 2026-03-09 01:54:57 -07:00
Kelsi
94a441e234 Advance DX12 bridge dispatch path and guard Win32 Vulkan handle exports 2026-03-09 01:49:18 -07:00