Commit graph

126 commits

Author SHA1 Message Date
Kelsi
4cbceced67 Fix invisible walls from WMO doodad M2 collision and MOPY filtering
WMO interior doodads (gears, decorations) were blocking player movement
via M2 collision. Skip collision for all WMO doodad M2 instances since
the WMO itself handles wall collision.

Also filter WMO wall collision using MOPY per-triangle flags: only
rendered+collidable triangles block the player, skipping invisible
collision hulls.

Revert tram portal extended range (no longer needed with collision fix).
2026-03-06 12:26:17 -08:00
Kelsi
84b04446c1 Per-instance NPC hair/skin textures, fix binary search float comparison
- NPC hair/skin textures now use per-instance overrides instead of shared
  model-level textures, so each NPC shows its own hair color/style
- Hair/skin DBC lookup runs for every NPC instance (including cached models)
  rather than only on first load
- Fix keyframe binary search to use float comparison matching original
  linear scan semantics
2026-03-04 09:19:02 -08:00
Kelsi
e6acb4ac9a Optimize animation hotpaths: binary keyframe search, eliminate sqrt calls
- Replace O(n) linear keyframe search with O(log n) binary search in both
  M2 and Character renderers (runs thousands of times per frame)
- Smoke particle removal: swap-and-pop instead of O(n²) vector erase
- Character render backface cull: eliminate sqrt via squared comparison
- Quaternion validation: use length² instead of sqrt-based length check
2026-03-04 08:33:56 -08:00
Kelsi
2e432fc123 Eliminate per-instance hash lookups in M2 render/shadow culling loops
Use cached model flags (isValid, isSmoke, isInvisibleTrap, isGroundDetail,
disableAnimation, boundRadius) on M2Instance instead of models.find() in
the hot culling paths. Also complete cached flag initialization in
createInstanceWithMatrix().
2026-03-04 08:28:21 -08:00
Kelsi
30fa9836d9 Fix glow sprite flashing, move fadeAlpha to push constants, throttle character bones
- Glow sprites now use dedicated vertex buffer (glowVB_) separate from
  M2 particle buffer to prevent data race when renderM2Particles()
  overwrites glow data mid-flight
- Move fadeAlpha from shared material UBO to per-draw push constants,
  eliminating cross-instance alpha race on non-double-buffered UBOs
- Smooth adaptive render distance transitions to prevent pop-in/out
  at instance count thresholds (1000/2000)
- Distance-tiered character bone throttling: near (<30u) every frame,
  mid (30-60u) every 3rd, far (60-120u) every 6th frame
- Skip weapon instance animation updates (transforms set by parent bones)
2026-03-04 08:17:32 -08:00
Kelsi
3482dacea8 Optimize M2 update loop: skip static doodads, incremental spatial index
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled
- Split M2 instances into fast-path index lists (animated, particle-only,
  particle-all, smoke) to avoid iterating all 46K instances per frame
- Cache model flags (hasAnimation, disableAnimation, isSmoke, etc.) on
  M2Instance struct to eliminate per-frame hash lookups
- Replace full rebuildSpatialIndex on position/transform updates with
  incremental grid cell remove+add, preventing 8.5ms/frame rebuild cost
- Advance animTime for all instances (texture UV animation) but only
  compute bones and particles for the ~3K that need it

M2_UPDATE: 10.7ms → 2.0ms, FPS: 35 → 55-59
2026-03-02 14:45:49 -08:00
Kelsi
48eb0b70a3 Fix GPU resource leaks and re-entrant world loading for instance transitions
Reset descriptor pools in CharacterRenderer/M2Renderer/WMORenderer on map
change to prevent VK_ERROR_DEVICE_LOST from pool exhaustion. Defer re-entrant
SMSG_NEW_WORLD during active world load to avoid recursive cleanup crashes.
Gate swim bubbles on swimming state, skip redundant shadow pipeline re-init,
add WOWEE_SKIP_* env vars for render isolation debugging.
2026-03-02 08:06:35 -08:00
Kelsi
956e2c8bb1 Reduce city stutter: lower spawn rate, resync interval, M2 render distance
- MAX_SPAWNS_PER_FRAME 8→3 (each spawn does sync M2 load, 5-50ms each)
- Creature resync scan interval 1s→3s (O(N) entity iteration)
- M2 render distance: add 1000+ instance tier at 500 units, reduce 2000+
  tier from 350→300 units to cap draw call count in dense cities
2026-02-25 12:16:55 -08:00
Kelsi
7ca9caa212 Fix Windows ARM64 build: disable x86 asm in StormLib's libtomcrypt
StormLib's bundled libtomcrypt uses x86 inline assembly (bswapl/movl)
gated by __MINGW32__, which is defined on CLANGARM64 too. Pass
-DLTC_NO_BSWAP to force portable C byte-swap fallback.
2026-02-25 03:06:06 -08:00
Kelsi
d47ae2a110 Fix city stuttering with incremental tile finalization and GPU optimizations
Replace monolithic finalizeTile() with a phased state machine that spreads
GPU upload work across multiple frames (TERRAIN→M2→WMO→WATER→AMBIENT→DONE).
Each advanceFinalization() call does one bounded unit of work within the
per-frame time budget, eliminating 50-300ms frame hitches when entering cities.

Additional performance improvements:
- Pre-allocate bone SSBOs at M2 instance creation instead of lazily during
  first render frame, preventing hitches when many skinned characters appear
- Enable WMO distance culling (800 units) with active-group exemption so
  the player's current floor/neighbors are never culled
- Add 4-tier adaptive M2 render distance (250/400/600/1000 based on count)
- Remove dead PendingM2Upload queue code superseded by incremental system

Fix tile re-enqueueing bug: keep tiles in pendingTiles until committed to
loadedTiles (not when moved to finalizingTiles_) so streamTiles() doesn't
re-enqueue tiles mid-finalization. Also handle unloadTile() for tiles in
the finalizingTiles_ deque to prevent orphaned water/M2/WMO resources.
2026-02-25 02:36:23 -08:00
Kelsi
2a1bd12f5b Fix game objects rendering with player textures
When M2Renderer's descriptor pool was exhausted, batch.materialSet
would be VK_NULL_HANDLE and the bind was skipped, but the draw call
still executed using the previously bound descriptor set from
CharacterRenderer — causing game objects to render with the player's
skin/armor textures. Skip the entire batch instead.
2026-02-23 20:41:06 -08:00
Kelsi
01c08b93b0 Exempt ambient creatures from foliage animation freeze
Fireflies, dragonflies, butterflies, and moths no longer get
disableAnimation/foliage classification so their bone animation
and particles run normally.
2026-02-23 07:21:45 -08:00
Kelsi
4db97e37b7 Add ambient insect particles near water vegetation, fix firefly particles, and improve water foam
- Spawn dark point-sprite insects buzzing around cattails/reeds/kelp/seaweed
- Fix firefly M2 particles: exempt from alpha dampening and forced gravity
- Make water shoreline/crest foam more irregular with UV warping and bluer tint
2026-02-23 07:18:44 -08:00
Kelsi
93f873b521 Allow texture load retries instead of permanently caching failures
Remove negative cache for transient load failures in M2, terrain, and
character renderers. Failed textures return white and will be retried
on next model/tile load when assets may have finished streaming.
2026-02-23 06:51:06 -08:00
Kelsi
efc7e65dfc Optimize M2/WMO render loop: cache UBO pointers, precompute model flags, reduce rebinds
- Cache material UBO mapped pointers at creation time, eliminating
  per-batch vmaGetAllocationInfo() calls in the hot render path
- Precompute foliage/elven/lantern/kobold model name classifications
  at load time instead of per-instance string operations every frame
- Remove redundant descriptor set and push constant rebinds on WMO
  pipeline switches (preserved across compatible layouts)
- Pre-allocate glow sprite descriptor set once at init instead of
  allocating from the pool every frame
2026-02-23 06:06:24 -08:00
Kelsi
77012adbc6 Add alpha-tested foliage shadows: per-batch texture binding and shadow map receiving
Shadow casting: foliage batches now bind their actual texture in the shadow
pass with alpha testing, producing leaf-shaped shadows instead of solid cards.
Uses a per-frame resettable descriptor pool for texture sets.

Shadow receiving: foliage fragments now sample the shadow map with PCF
instead of using a flat constant darkening.
2026-02-23 05:55:03 -08:00
Kelsi
58681753e5 Freeze gameobject M2 animations to prevent cycling
Gameobject M2 instances (books, crates, chests) were continuously
cycling their animations because M2Renderer unconditionally loops
all sequences. Added setInstanceAnimationFrozen() and freeze all
gameobject instances at creation time so they stay in their bind pose.
2026-02-23 05:31:02 -08:00
Kelsi
7dc9bf3766 Fix M2 bone buffer leak on instance removal
removeInstance() and removeInstances() were erasing M2Instances without
calling destroyInstanceBones(), leaking VMA bone buffers permanently.
This caused framerate to drop and never recover after NPC encounters.
2026-02-23 04:52:40 -08:00
Kelsi
2124761ea8 Add distance culling to shadow passes for CPU-bound shadow perf
All three shadow renderers (WMO, M2, Character) were iterating every
loaded instance with zero culling. Now skip instances outside the
180-unit shadow frustum radius via squared-distance check.
2026-02-23 04:48:26 -08:00
Kelsi
9e1a913060 Increase texture cache budgets to 4GB and cap repetitive warnings
Raise all texture cache defaults from 1GB to 4GB to reduce rejections.
Cap cache-full warnings (texture + model) to 3 messages per renderer,
and cap update block parse errors to 5 messages.
2026-02-23 04:32:58 -08:00
Kelsi
e8c2344226 Remove leftover debug logging from render hot paths
Strip per-frame/periodic logging from CharacterRenderer (batch dump,
instance count) and M2Renderer (frame timing profiler) to avoid
unnecessary string formatting and I/O in render loops.
2026-02-23 04:18:35 -08:00
Kelsi
ef1e5abe8e Add shader-driven tree beautification: wind sway, SSS, color variation, AO
- Vertex wind animation: 3-layer displacement (trunk/branch/leaf) with
  quadratic height scaling so bases stay grounded
- Shadow pass: matching vertex displacement split into foliage/non-foliage
  passes, removed UV-wiggle approach
- Leaf subsurface scattering: warm backlit glow when looking toward sun
- Per-instance color variation: hue/brightness from position hash via flat
  varying to avoid interpolation flicker
- Canopy ambient occlusion: height-based darkening of tree interiors
- Detail normal perturbation: UV-only procedural normals to break flat cards
- Bayer 4x4 ordered dither replacing sin-hash noise for alpha edges
- Foliage skips shadow map sampling and specular to prevent flicker from
  swaying geometry sampling unstable shadow/highlight values
2026-02-23 03:53:50 -08:00
Kelsi
67e63653a4 Stabilize Vulkan shadow pipeline diagnostics and compatibility path
- Fix shadow depth image layout transitions by tracking per-frame old/new layouts.
- Update receiver shadow projection to Vulkan clip-depth convention.
- Test inverted shadow compare op path (GREATER_OR_EQUAL).
- Switch shadow compare samplers to NEAREST filtering for broader Vulkan compatibility.
- Expand shadow caster coverage by disabling caster cull filtering in WMO/M2/Character shadow pipelines.
- Keep light-space matrix path on stable character-centered framing.
2026-02-22 10:25:33 -08:00
Kelsi
2c5e0dd313 Fix Vulkan shadow light direction and restore ground-clutter cutout visibility 2026-02-22 09:47:39 -08:00
Kelsi
bd0305f6dd Stabilize Vulkan rendering state for minimap, foliage, and water 2026-02-22 09:34:27 -08:00
Kelsi
8efc1548dc Fix minimap arrow orientation and ground-detail foliage transparency 2026-02-22 08:44:16 -08:00
Kelsi
9c8cd44803 Optimize threading and texture fallback stability 2026-02-22 08:12:08 -08:00
Kelsi
6d55c19987 Stabilize net parsing and reduce texture-cache churn 2026-02-22 07:44:32 -08:00
Kelsi
ae88b226b5 Stabilize streaming memory and parser handling; revert socket recv optimizations 2026-02-22 07:26:54 -08:00
Kelsi
fa1867cf2f Fix MSAA 8x crash and eliminate redundant GPU stalls
- Add error handling: revert to 1x if recreateSwapchain fails
- Clamp requested MSAA to device maximum before applying
- Retry MSAA color image allocation without TRANSIENT on failure
- Remove redundant vkDeviceWaitIdle from WMO/M2/Character recreatePipelines
  (caller already waits once, was causing ~13 stalls instead of 1)
2026-02-22 03:05:55 -08:00
Kelsi
e12141a673 Add configurable MSAA anti-aliasing, update auth screen and terrain shader
- MSAA: conditional 2-att (off) vs 3-att (on) render pass with auto-resolve
- MSAA: multisampled color+depth images, query max supported sample count
- MSAA: .setMultisample() on all 25+ main-pass pipelines across 17 renderers
- MSAA: recreatePipelines() on every sub-renderer for runtime MSAA changes
- MSAA: Renderer::setMsaaSamples() orchestrates swapchain+pipeline+ImGui rebuild
- MSAA: Anti-Aliasing combo (Off/2x/4x/8x) in Video settings, persisted
- Update auth screen assets and terrain fragment shader
2026-02-22 02:59:24 -08:00
Kelsi
83b576e8d9 Vulcan Nightmare
Experimentally bringing up vulcan support
2026-02-21 22:04:17 -08:00
Kelsi
fa3060bdf7 Harden runtime against stutter-inducing log floods and missing display IDs
- Re-gate M2 glow diagnostics behind WOWEE_M2_GLOW_DIAG and DEBUG

- Deduplicate missing/failed texture warnings in asset and M2 texture loaders

- Deduplicate unhandled opcode warnings by state/opcode key in non-IN_WORLD phases

- Throttle malformed spline point-count warnings across world/classic/tbc parsers

- Ignore suspiciously huge display IDs from malformed packets with throttled warning

- Add nearest-known displayId model fallback cache for missing creature display mappings

- Clear display fallback caches on expansion reload and logout
2026-02-21 04:05:53 -08:00
Kelsi
dc91b316ed Refine lantern glow-card replacement and preserve lamp geometry
- Add per-batch glow metadata (lantern hint, card-like classification, tint)

- Track normalized texture keys and log lantern/light texture sets once for diagnostics

- Force sprite replacement for known Stormwind/Night Elf glow textures

- Keep lantern/light meshes visible while hiding only classified glow-card submeshes

- Choose glow sprite tint from texture hints (cool/red/warm) to avoid orange-only cards

- Broaden lantern glow detection to handle gameobject lights with nonstandard material setups
2026-02-21 03:51:42 -08:00
Kelsi
f8fc34ff2c Narrow glow-card replacement to preserve lamp/sconce textures
- restrict glow sprite substitution to elven-like light models only
- keep Stormwind lamps and generic torch sconces rendering authored glass/grate/flame cards
- remove over-broad flame heuristic that turned many light fixtures into plain glow orbs
2026-02-21 03:26:21 -08:00
Kelsi
9da875c8ba Fix elven lantern glow cards rendering as flat disks
- route small lantern/lamp/torch/candle emissive batches to glow-sprite path
- broaden light-emitter detection beyond additive-only blend modes
- add a secondary wider low-alpha halo layer for softer glow falloff
- keep elven-style lantern tint in cool blue while preserving warm tint elsewhere

This avoids rendering hard flat glow planes and restores a softer volumetric-looking lantern glow.
2026-02-21 02:49:26 -08:00
Kelsi
0c8798d6b5 Improve player and foliage shadow quality and stability
- ensure player transform sync is not gated by third-person so player shadow stays consistent

- hold shadow projection center during movement and snap once on stop to remove delayed catch-up

- smooth foliage caster transitions using blended phase-shifted UV samples

- tune foliage motion frequencies/amplitudes for less popping

- increase shadow map resolution to 2048 and retune terrain PCF texel scale

- increase global shadow strength from 0.62 to 0.68 for stronger, clearer shadows
2026-02-21 02:28:47 -08:00
Kelsi
7717ab8d6b Stabilize foliage shadows and smooth motion transitions
- keep shadow projection center fixed while moving to remove per-frame projection churn flicker

- replace delayed post-move catch-up with immediate stop transition and idle smoothing

- rework foliage shadow caster motion to use blended phase-shifted UV samples for continuous position transitions

- reduce high-frequency foliage threshold popping by removing threshold warping path

- sharpen terrain receive filtering with tuned 5-tap PCF weights/offset for more detailed shadows

- raise shadow map resolution to 1536 and keep light-space texel snapping for stable sampling

- set shadows enabled by default and lower global shadow strength from 0.65 to 0.62

- keep foliage animation speed consistent between moving and idle at 80%
2026-02-21 02:23:08 -08:00
Kelsi
1003b25ff4 Improve runtime stutter handling and ground clutter performance
- reduce per-tile ground clutter generation pressure and enforce tighter caps to avoid spikes

- remove expensive detail dedupe scans from the hot render path

- add progressive/lazy clutter updates around player movement to smooth frame pacing

- lower noisy runtime INFO logging to DEBUG/throttled paths

- keep terrain/game screen updates responsive while preserving existing behavior
2026-02-21 01:26:16 -08:00
Kelsi
3368dbb9ec Fix NPC apparel fallback and reduce world-entry stutter
Hide NPC cloak/object-skin mesh when no cape texture resolves by using a transparent texture fallback, preventing skin-texture bleed on cloaks. Tighten NPC equipment region compositing by slot and add safe humanoid geoset selection to avoid robe-over-pants conflicts and odd pants texturing.

Reduce login/runtime hitching by deferring non-critical world-system initialization across frames, lowering per-frame transport doodad spawn budget, and demoting high-volume transport/MO_TRANSPORT diagnostics to debug. Gate M2 glow diagnostics behind WOWEE_M2_GLOW_DIAG and make zone music prewarm opt-in via WOWEE_PREWARM_ZONE_MUSIC.
2026-02-20 20:31:04 -08:00
Kelsi
da49593268 Add 3D level-up effect using LevelUp.m2 spell model
Replace 2D screen-space ding rings with real WoW LevelUp.m2 particle/geometry
effect. Fix FBlock particle color parsing (C3Vector floats, not CImVector bytes)
which was producing blue/red instead of golden yellow. Spell effect models bypass
particle dampeners, glow sprite conversion, Mod→Additive blend override, and all
collision (floor/wall/camera) to prevent camera zoom-in. Other players' level-ups
trigger the 3D effect at their position with group chat notification. F7 hotkey
for testing.
2026-02-19 20:36:25 -08:00
Kelsi
6aac80e5b1 Fix black glow cards on streetlamps: discard dark pixels in Mod blend batches
Mod blend (GL_DST_COLOR, GL_ZERO) multiplies the framebuffer by texture color,
so dark pixels create visible black rectangles. Use a variable colorKeyThreshold
uniform (0.7 for Mod/Mod2x, 0.08 default) to discard dark pixels from these
batches while preserving normal colorKeyBlack behavior elsewhere.
2026-02-19 19:07:58 -08:00
Kelsi
d2ff91435a Revert glow pixel detection and forced additive override, add diagnostics
The pixel content glow detection (>60% dark = glow) was too aggressive,
flagging dark metal textures on sconces as glow textures and making
structural geometry transparent. The forced additive blending for
colorKeyBlack batches compounded the issue.

Reverted both. Added per-batch diagnostic logging for models containing
"light", "lamp", or "lantern" to identify the actual blend modes and
material flags on Stormwind bridge lamps.
2026-02-19 18:30:34 -08:00
Kelsi
b2d43f702f Fix Stormwind bridge lamp glow: detect glow textures by pixel content,
force additive blending for colorKeyBlack batches

Two key changes:

1. Detect glow-like textures by analyzing pixel content during loading:
   textures that are >60% near-black with some bright pixels are flagged
   as colorKeyBlack regardless of filename. This catches glow textures
   like Stormwind street lamps whose paths don't contain keywords like
   "lamp" or "lantern".

2. Force additive blending (mode 3) for batches with colorKeyBlack
   textures that have blendMode 1 or 2. These textures are designed for
   additive blending where black = transparent, but some M2 files specify
   Alpha or AlphaKey blend modes which cause black areas to render as
   solid dark disks instead of being invisible.
2026-02-19 18:27:21 -08:00
Kelsi
32cc13d1b2 Fix torch models eaten by glow sprites, fix lantern glow black backgrounds
Two fixes:

1. shouldUseGlowSprite now requires the UNLIT material flag (0x01) for
   the colorKeyBlack+flameLikeModel path. Previously, structural geometry
   (torch handles, sconce brackets) on flame-like models got replaced
   with glow sprites because their texture paths contained keywords like
   "torch" in the directory name, setting colorKeyBlack on non-glow
   textures. Requiring UNLIT ensures only actual glow/emissive batches
   become sprites while lit structural geometry renders normally.

2. Fragment shader now discards near-black (maxRGB < 0.1) for ALL unlit
   non-opaque batches, not just additive blend modes. Glow effects on
   lanterns/lamps that use blendMode 1 (AlphaKey) or 2 (Alpha) instead
   of 3 (Additive) now properly discard their black backgrounds.
2026-02-19 18:23:59 -08:00
Kelsi
cc8b06d1e4 Fix black background on lamp/lantern/torch glow effects
Three-part fix for glow textures showing opaque black rectangles instead
of being transparent:

1. Pass blend mode to fragment shader via uBlendMode uniform. For additive
   blend modes (3=Add, 6=BlendAdd), discard near-black fragments (maxRGB
   < 0.1) since they contribute nothing visually but render as dark
   rectangles against sky/terrain.

2. Expand colorKeyBlack texture keyword detection to include "lamp",
   "lantern", "glow", "flare", "brazier", "campfire", "bonfire" in
   addition to the existing "candle", "flame", "fire", "torch".

3. Expand flameLikeModel detection for glow sprite conversion to include
   "brazier", "campfire", "bonfire". Also compute glow centers for
   colorKeyBlack batches (not just blendMode >= 3) so glow sprites
   position correctly for all flame-like objects.
2026-02-19 18:19:52 -08:00
Kelsi
0ea1106b05 Tune M2 lantern flame glow without restoring card artifacts 2026-02-19 06:12:32 -08:00
Kelsi
8d4d9b7169 Fix quest flow regressions, tooltip compare stats, and M2 alpha-key handling 2026-02-19 02:27:01 -08:00
Kelsi
a30525d7c9 Fix WMO visibility culling and renderer initialization guards 2026-02-18 22:41:05 -08:00
Kelsi
514b914068 Add shadow frustum culling to terrain and M2 depth passes
Both passes were rendering the entire loaded scene (17×17 tile radius)
into a shadow map that only covers 360×360 world units — submitting
10-50× more geometry than the shadow frustum can actually use.

- TerrainRenderer::renderShadow: skip chunks whose bounding sphere
  doesn't overlap the shadow frustum AABB in XY. Reduces terrain draw
  calls from O(all loaded chunks) to O(chunks within ~180 units).
- M2Renderer::renderShadow: skip instances whose world AABB doesn't
  overlap the shadow frustum in XY. Reduces M2 draw calls similarly.
- Both functions now take shadowCenter + halfExtent parameters.
2026-02-18 21:15:24 -08:00