wmo_renderer: when portal BFS starts from a group with no portal refs
(utility/transition group), the rest of the WMO becomes invisible because
BFS only adds the starting group. Fix: if cameraGroup has portalCount==0,
fall back to marking all groups visible (same as camera-outside behavior).
renderer: minimap player-orientation arrow was pointing the wrong direction.
The shader convention is arrowRotation=0→North, positive→clockwise (West),
negative→East. The correct mapping from canonical yaw is arrowRotation =
-canonical_yaw. Fixed both render paths (cameraController and gameHandler)
in both the FXAA and non-FXAA minimap render calls.
World-map W-key: already corrected in prior commit (13c096f); users with
stale ~/.wowee/settings.cfg should rebind via Settings > Controls.
Parse M2RibbonEmitter data (WotLK format) from M2 files — bone index,
position, color/alpha/height tracks, edgesPerSecond, edgeLifetime,
gravity. Add CPU-side trail simulation per instance (edge birth at bone
world position, lifetime expiry, gravity droop). New m2_ribbon.vert/frag
shaders render a triangle-strip quad per emitter using the existing
particleTexLayout_ descriptor set. Supports both alpha-blend and additive
pipeline variants based on material blend mode. Fixes invisible spell
trail effects (~5-10%% of spell visuals) that were silently skipped.
- FXAA path: repurpose _pad field as 'desaturate' push constant; when
ghostMode_ is true, convert final pixel to grayscale with slight cool
blue tint using luma(0.299,0.587,0.114) mix
- Non-FXAA path: apply a high-opacity gray overlay (rgba 0.5,0.5,0.55,0.82)
over the scene for a washed-out look
- Both parallel (SEC_POST) and single-threaded render paths covered
- ghostMode_ flag set each frame from gameHandler->isPlayerGhost()
- Post-FXAA unsharp mask: when FSR2 is active alongside FXAA, forward
the FSR2 sharpness value (0–2) to the FXAA fragment shader via a new
vec4 push constant. A contrast-adaptive sharpening step (unsharp mask
scaled to 0–0.3) is applied after FXAA blending, recovering the
crispness that FXAA's sub-pixel blend removes. At sharpness=2.0 the
output matches RCAS quality; at sharpness=0 the step is a no-op.
- MSAA guard: setFXAAEnabled() refuses to activate FXAA when hardware
MSAA is in use. FXAA's role is to supplement FSR temporal AA, not to
stack on top of MSAA which already resolves jaggies during the scene
render pass.
FSR EASU and FSR2 sharpen fragment shaders had a manual Y-flip to undo
the now-removed postprocess.vert flip. Strip those since the vertex
shader no longer flips, making all postprocess paths consistent.
Also flip the default mouse Y-axis to match user expectation (mouse
down = look up / flight-sim style) and make FSR1 disable MSAA on
enable, matching FSR2 behaviour (FSR provides its own spatial AA).
- Remove !fsr_.enabled / !fsr2_.enabled guards that blocked FXAA init
- FXAA can now coexist with FSR1 and FSR3 simultaneously
- Priority: FSR3 > FXAA > FSR1
- FSR3 + FXAA: scene renders at FSR3 internal res, temporal AA runs,
then FXAA reads FSR3 history and applies spatial AA to swapchain
(replaces RCAS sharpening for ultra-quality native mode)
- FXAA + FSR1: scene renders at native res, FXAA post-processes;
FSR1 resources exist but are idle (FXAA wins for better quality)
- FSR3 only / FSR1 only: unchanged paths
- Fix missing fxaa.frag.spv: shader was present but uncompiled; the
CMake compile_shaders() function will now pick it up on next build
Floating-point fmod() loses precision with large accumulated time values, causing
subtle jumps/hitches in animation loops. Replace with iterative duration subtraction
to keep animationTime bounded and maintain precision, consistent with the fix
applied to character_renderer.cpp.
Applies to:
- M2 creature/object animation loops (main update)
- M2 particle-only instance wrapping (3333ms limit)
- M2 global sequence timing resolution
- M2 animated particle tile indexing
- Mount bobbing motion (sinusoidal rider motion)
- Character footstep trigger timing
- Mount footstep trigger timing
All timing computations now use the same precision-preserving approach.
- WotLK opcode 0x21E is aliased to both SMSG_SET_REST_START and
SMSG_QUEST_FORCE_REMOVE. In WotLK, treat as SET_REST_START (non-zero
= entering rest area, zero = leaving); Classic/TBC treat as quest removal.
- PLAYER_BYTES_2 rest state byte: change from `& 0x01` to `!= 0` to also
detect REST_TYPE_IN_CITY (value 2), not just REST_TYPE_IN_TAVERN (1).
- Minimap arrow: server orientation (π/2=North) needed conversion to
minimap arrow space (0=North). Subtract π/2 in both render paths so
arrow points North when player faces North.
- renderer: construct QuestMarkerRenderer via make_unique (was never
instantiated, causing getQuestMarkerRenderer() to always return null
and all quest-marker updates to be silently skipped)
- m2_renderer: add "levelup" to effectByName so LevelUp.m2 is treated
as a spell effect (additive blend, no collision, particle-dominated)
- renderer: auto-cancel non-looping emote animations when they reach
end-of-sequence, transitioning player back to IDLE state
- wmo_renderer: pass character position (not camera position) to portal
visibility traversal — the 3rd-person camera can orbit outside a WMO
while the character is inside, causing interior groups to cull; render()
now accepts optional viewerPos that defaults to camPos for compatibility
- renderer: pass &characterPosition to wmoRenderer->render() at both
main and single-threaded call sites; reflection pass keeps camPos
- renderer: apply mount pitch/roll to rider during all flight, not just
taxiFlight_ (fixes zero rider tilt during player-controlled flying)
- game_screen: format SAY/YELL/WHISPER/EMOTE using WoW-style "Name says:"
instead of "[SAY] Name:" bracket prefix
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.
- 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.
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.
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.
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.
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).
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().
- 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
- Motion vectors: single unjittered reprojection matrix (80 bytes) instead of
two jittered matrices (160 bytes), eliminating numerical instability from
jitter amplification through large world coordinates
- Sharpen pass: fix Y-flip for correct UV sampling, double-buffer descriptor
sets to avoid race with in-flight command buffers
- MSAA: auto-disable when FSR2 enabled, grey out AA setting in UI
- Accumulation: variance-based neighborhood clamping in YCoCg space,
correct history layout transitions
- Frame index: wrap at 256 for stable Halton sequence