Kelsidavis-WoWee/include/rendering/renderer.hpp

459 lines
19 KiB
C++
Raw Normal View History

#pragma once
#include <memory>
#include <string>
#include <cstdint>
#include <vector>
#include <future>
#include <cstddef>
#include <unordered_map>
#include <unordered_set>
#include <glm/glm.hpp>
#include <vulkan/vulkan.h>
#include <vk_mem_alloc.h>
#include "rendering/vk_frame_data.hpp"
#include "rendering/vk_utils.hpp"
#include "rendering/sky_system.hpp"
namespace wowee {
namespace core { class Window; }
namespace rendering { class VkContext; }
namespace game { class World; class ZoneManager; class GameHandler; }
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
namespace audio { class AudioCoordinator; }
namespace pipeline { class AssetManager; }
namespace rendering {
class Camera;
class CameraController;
class TerrainRenderer;
class TerrainManager;
class PerformanceHUD;
class WaterRenderer;
class Skybox;
class Celestial;
class StarField;
class Clouds;
class LensFlare;
class Weather;
class Lightning;
class LightingManager;
class SwimEffects;
class MountDust;
class LevelUpEffect;
class ChargeEffect;
class CharacterRenderer;
class WMORenderer;
class M2Renderer;
class Minimap;
class WorldMap;
class QuestMarkerRenderer;
class CharacterPreview;
class AmdFsr3Runtime;
class SpellVisualSystem;
class PostProcessPipeline;
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
class AnimationController;
feat(animation): 452 named constants, 30-phase character animation state machine Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND, anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1) lookup, and flyVariant() compact 218-element ground→FLY_* resolver. Expand AnimationController into a full state machine with 20+ named states: spell cast (directed→omni→cast fallback chain, instant one-shot release), hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle, stealth animation substitution, loot, fishing channel, sit/sleep/kneel down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons (BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY, vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS), emote state variants, off-hand/pierce/dual-wield alternation, NPC birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell. Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo (12 constants) namespaces; replace all magic numbers in spell_handler.cpp. Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire GameObjectStateCallback. Add DBC cross-validation on world entry. Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and asset_pipeline_gui.py. Add tests/test_animation_ids.cpp. Bug fixes included: - Stand state 1 was animating READY_2H(27) — fixed to SITTING(97) - Spell casts ended freeze-frame — add one-shot release animation - NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff) - Chair sits (states 2/4/5/6) incorrectly played floor-sit transition - STOP(3) used for all spell casts — replaced with model-aware chain
2026-04-04 23:02:53 +03:00
enum class RangedWeaponType : uint8_t;
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
class LevelUpEffect;
class ChargeEffect;
class SwimEffects;
feat(rendering): GPU architecture + visual quality fixes M2 GPU instancing - M2InstanceGPU SSBO (96 B/entry, double-buffered, 16384 max) - Group opaque instances by (modelId, LOD); single vkCmdDrawIndexed per group - boneBase field indexes into mega bone SSBO via gl_InstanceIndex Indirect terrain drawing - 24 MB mega index buffer (6M uint32) + 64 MB mega vertex buffer - CPU builds VkDrawIndexedIndirectCommand per visible chunk - Single VB/IB bind per frame; shadow pass reuses mega buffers - Replaced vkCmdDrawIndexedIndirect with direct vkCmdDrawIndexed to fix host-mapped buffer race condition that caused terrain flickering GPU frustum culling (compute shader) - m2_cull.comp.glsl: 64-thread workgroups, sphere-vs-6-planes + distance cull - CullInstanceGPU SSBO input, uint visibility[] output, double-buffered - dispatchCullCompute() runs before main pass via render graph node Consolidated bone matrix SSBOs - 16 MB double-buffered mega bone SSBO (2048 instances × 128 bones) - Eliminated per-instance descriptor sets; one megaBoneSet_ per frame - prepareRender() packs bone matrices consecutively into current frame slot Render graph / frame graph - RenderGraph: RGResource handles, RGPass nodes, Kahn topological sort - Automatic VkImageMemoryBarrier/VkBufferMemoryBarrier between passes - Passes: minimap_composite, worldmap_composite, preview_composite, shadow_pass, reflection_pass, compute_cull - beginFrame() uses buildFrameGraph() + renderGraph_->execute(cmd) Pipeline derivatives - PipelineBuilder::setFlags/setBasePipeline for VK_PIPELINE_CREATE_DERIVATIVE_BIT - M2 opaque = base; alphaTest/alpha/additive are derivatives - Applied to terrain (wireframe) and WMO (alpha-test) renderers Rendering bug fixes: - fix(shadow): compute lightSpaceMatrix before updatePerFrameUBO to eliminate one-frame lag that caused shadow trails and flicker on moving objects - fix(shadow): scale depth bias with shadowDistance_ instead of hardcoded 0.8f to prevent acne at close range and gaps at far range - fix(visibility): WMO group distance threshold 500u → 1200u to match terrain view distance; buildings were disappearing on the horizon - fix(precision): camera near plane 0.05 → 0.5 (ratio 600K:1 → 60K:1), eliminating Z-fighting and improving frustum plane extraction stability - fix(streaming): terrain load radius 4 → 6 tiles (~2133u → ~3200u) to exceed M2 render distance (2800u) and eliminate pop-in when camera turns; unload radius 7 → 9; spawn radius 3 → 4 - fix(visibility): ground-detail M2 distance multiplier 0.75 → 0.9 to reduce early pop of grass and debris
2026-04-04 13:43:16 +03:00
class RenderGraph;
class Renderer {
public:
Renderer();
~Renderer();
bool initialize(core::Window* window);
void shutdown();
void beginFrame();
void endFrame();
void renderWorld(game::World* world, game::GameHandler* gameHandler = nullptr);
/**
* Update renderer (camera, etc.)
*/
void update(float deltaTime);
/**
* Load test terrain for debugging
* @param assetManager Asset manager to load terrain data
* @param adtPath Path to ADT file (e.g., "World\\Maps\\Azeroth\\Azeroth_32_49.adt")
*/
bool loadTestTerrain(pipeline::AssetManager* assetManager, const std::string& adtPath);
/**
* Initialize all sub-renderers (WMO, M2, Character, terrain, water, minimap, etc.)
* without loading any ADT tile. Used by WMO-only maps (dungeons/raids/BGs).
*/
bool initializeRenderers(pipeline::AssetManager* assetManager, const std::string& mapName);
/**
* Enable/disable terrain rendering
*/
void setTerrainEnabled(bool enabled) { terrainEnabled = enabled; }
/**
* Enable/disable wireframe mode
*/
void setWireframeMode(bool enabled);
/**
* Load terrain tiles around position
* @param mapName Map name (e.g., "Azeroth", "Kalimdor")
* @param centerX Center tile X coordinate
* @param centerY Center tile Y coordinate
* @param radius Load radius in tiles
*/
bool loadTerrainArea(const std::string& mapName, int centerX, int centerY, int radius = 1);
/**
* Enable/disable terrain streaming
*/
void setTerrainStreaming(bool enabled);
/**
* Render performance HUD
*/
void renderHUD();
Camera* getCamera() { return camera.get(); }
CameraController* getCameraController() { return cameraController.get(); }
TerrainRenderer* getTerrainRenderer() const { return terrainRenderer.get(); }
TerrainManager* getTerrainManager() const { return terrainManager.get(); }
PerformanceHUD* getPerformanceHUD() { return performanceHUD.get(); }
WaterRenderer* getWaterRenderer() const { return waterRenderer.get(); }
Skybox* getSkybox() const { return skySystem ? skySystem->getSkybox() : nullptr; }
Celestial* getCelestial() const { return skySystem ? skySystem->getCelestial() : nullptr; }
StarField* getStarField() const { return skySystem ? skySystem->getStarField() : nullptr; }
Clouds* getClouds() const { return skySystem ? skySystem->getClouds() : nullptr; }
LensFlare* getLensFlare() const { return skySystem ? skySystem->getLensFlare() : nullptr; }
Weather* getWeather() const { return weather.get(); }
Lightning* getLightning() const { return lightning.get(); }
CharacterRenderer* getCharacterRenderer() const { return characterRenderer.get(); }
WMORenderer* getWMORenderer() const { return wmoRenderer.get(); }
M2Renderer* getM2Renderer() const { return m2Renderer.get(); }
Minimap* getMinimap() const { return minimap.get(); }
WorldMap* getWorldMap() const { return worldMap.get(); }
QuestMarkerRenderer* getQuestMarkerRenderer() const { return questMarkerRenderer.get(); }
SkySystem* getSkySystem() const { return skySystem.get(); }
const std::string& getCurrentZoneName() const { return currentZoneName; }
bool isPlayerIndoors() const { return playerIndoors_; }
VkContext* getVkContext() const { return vkCtx; }
VkDescriptorSetLayout getPerFrameSetLayout() const { return perFrameSetLayout; }
VkRenderPass getShadowRenderPass() const { return shadowRenderPass; }
// Third-person character follow
void setCharacterFollow(uint32_t instanceId);
glm::vec3& getCharacterPosition() { return characterPosition; }
uint32_t getCharacterInstanceId() const { return characterInstanceId; }
float getCharacterYaw() const { return characterYaw; }
void setCharacterYaw(float yawDeg) { characterYaw = yawDeg; }
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
// Emote support — delegates to AnimationController (§4.2)
void playEmote(const std::string& emoteName);
void triggerLevelUpEffect(const glm::vec3& position);
void cancelEmote();
// Screenshot capture — copies swapchain image to PNG file
bool captureScreenshot(const std::string& outputPath);
// Spell visual effects (SMSG_PLAY_SPELL_VISUAL / SMSG_PLAY_SPELL_IMPACT)
// Delegates to SpellVisualSystem (owned by Renderer)
void playSpellVisual(uint32_t visualId, const glm::vec3& worldPosition,
bool useImpactKit = false);
SpellVisualSystem* getSpellVisualSystem() const { return spellVisualSystem_.get(); }
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
bool isEmoteActive() const;
2026-02-07 20:02:14 -08:00
static std::string getEmoteText(const std::string& emoteName, const std::string* targetName = nullptr);
static uint32_t getEmoteDbcId(const std::string& emoteName);
static std::string getEmoteTextByDbcId(uint32_t dbcId, const std::string& senderName, const std::string* targetName = nullptr);
static uint32_t getEmoteAnimByDbcId(uint32_t dbcId);
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
// Targeting support — delegates to AnimationController (§4.2)
void setTargetPosition(const glm::vec3* pos);
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
void setInCombat(bool combat);
void resetCombatVisualState();
bool isMoving() const;
void triggerMeleeSwing();
feat(animation): 452 named constants, 30-phase character animation state machine Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND, anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1) lookup, and flyVariant() compact 218-element ground→FLY_* resolver. Expand AnimationController into a full state machine with 20+ named states: spell cast (directed→omni→cast fallback chain, instant one-shot release), hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle, stealth animation substitution, loot, fishing channel, sit/sleep/kneel down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons (BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY, vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS), emote state variants, off-hand/pierce/dual-wield alternation, NPC birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell. Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo (12 constants) namespaces; replace all magic numbers in spell_handler.cpp. Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire GameObjectStateCallback. Add DBC cross-validation on world entry. Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and asset_pipeline_gui.py. Add tests/test_animation_ids.cpp. Bug fixes included: - Stand state 1 was animating READY_2H(27) — fixed to SITTING(97) - Spell casts ended freeze-frame — add one-shot release animation - NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff) - Chair sits (states 2/4/5/6) incorrectly played floor-sit transition - STOP(3) used for all spell casts — replaced with model-aware chain
2026-04-04 23:02:53 +03:00
void setEquippedWeaponType(uint32_t inventoryType, bool is2HLoose = false,
bool isFist = false, bool isDagger = false,
bool hasOffHand = false, bool hasShield = false);
void triggerSpecialAttack(uint32_t spellId);
void setEquippedRangedType(RangedWeaponType type);
void triggerRangedShot();
RangedWeaponType getEquippedRangedType() const;
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
void setCharging(bool charging);
bool isCharging() const;
void startChargeEffect(const glm::vec3& position, const glm::vec3& direction);
void emitChargeEffect(const glm::vec3& position, const glm::vec3& direction);
void stopChargeEffect();
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
// Mount rendering — delegates to AnimationController (§4.2)
void setMounted(uint32_t mountInstId, uint32_t mountDisplayId, float heightOffset, const std::string& modelPath = "");
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
void setTaxiFlight(bool onTaxi);
void setMountPitchRoll(float pitch, float roll);
void clearMount();
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
bool isMounted() const;
// AnimationController access (§4.2)
AnimationController* getAnimationController() const { return animationController_.get(); }
LevelUpEffect* getLevelUpEffect() const { return levelUpEffect.get(); }
ChargeEffect* getChargeEffect() const { return chargeEffect.get(); }
SwimEffects* getSwimEffects() const { return swimEffects.get(); }
// Selection circle for targeted entity
void setSelectionCircle(const glm::vec3& pos, float radius, const glm::vec3& color);
void clearSelectionCircle();
// CPU timing stats (milliseconds, last frame).
double getLastUpdateMs() const { return lastUpdateMs; }
double getLastRenderMs() const { return lastRenderMs; }
double getLastCameraUpdateMs() const { return lastCameraUpdateMs; }
double getLastTerrainRenderMs() const { return lastTerrainRenderMs; }
double getLastWMORenderMs() const { return lastWMORenderMs; }
double getLastM2RenderMs() const { return lastM2RenderMs; }
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
// Audio coordinator — owned by Application, set via setAudioCoordinator().
void setAudioCoordinator(audio::AudioCoordinator* ac) { audioCoordinator_ = ac; }
audio::AudioCoordinator* getAudioCoordinator() { return audioCoordinator_; }
game::ZoneManager* getZoneManager() { return zoneManager.get(); }
LightingManager* getLightingManager() { return lightingManager.get(); }
private:
void runDeferredWorldInitStep(float deltaTime);
core::Window* window = nullptr;
std::unique_ptr<Camera> camera;
std::unique_ptr<CameraController> cameraController;
std::unique_ptr<TerrainRenderer> terrainRenderer;
std::unique_ptr<TerrainManager> terrainManager;
std::unique_ptr<PerformanceHUD> performanceHUD;
std::unique_ptr<WaterRenderer> waterRenderer;
std::unique_ptr<Skybox> skybox;
std::unique_ptr<Celestial> celestial;
std::unique_ptr<StarField> starField;
std::unique_ptr<Clouds> clouds;
std::unique_ptr<LensFlare> lensFlare;
std::unique_ptr<Weather> weather;
std::unique_ptr<Lightning> lightning;
std::unique_ptr<LightingManager> lightingManager;
std::unique_ptr<SkySystem> skySystem; // Coordinator for sky rendering
std::unique_ptr<SwimEffects> swimEffects;
std::unique_ptr<MountDust> mountDust;
std::unique_ptr<LevelUpEffect> levelUpEffect;
std::unique_ptr<ChargeEffect> chargeEffect;
std::unique_ptr<CharacterRenderer> characterRenderer;
std::unique_ptr<WMORenderer> wmoRenderer;
std::unique_ptr<M2Renderer> m2Renderer;
std::unique_ptr<Minimap> minimap;
std::unique_ptr<WorldMap> worldMap;
std::unique_ptr<QuestMarkerRenderer> questMarkerRenderer;
audio::AudioCoordinator* audioCoordinator_ = nullptr; // Owned by Application
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
std::unique_ptr<AnimationController> animationController_; // §4.2
std::unique_ptr<game::ZoneManager> zoneManager;
// Shadow mapping (Vulkan)
static constexpr uint32_t SHADOW_MAP_SIZE = 4096;
// Per-frame shadow resources: each in-flight frame has its own depth image and
// framebuffer so that frame N's shadow read and frame N+1's shadow write don't
// race on the same image across concurrent GPU submissions.
// Array size must match MAX_FRAMES (= 2, defined in the private section below).
VkImage shadowDepthImage[2] = {};
VmaAllocation shadowDepthAlloc[2] = {};
VkImageView shadowDepthView[2] = {};
VkSampler shadowSampler = VK_NULL_HANDLE;
VkRenderPass shadowRenderPass = VK_NULL_HANDLE;
VkFramebuffer shadowFramebuffer[2] = {};
VkImageLayout shadowDepthLayout_[2] = {};
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
glm::vec3 shadowCenter = glm::vec3(0.0f);
bool shadowCenterInitialized = false;
bool shadowsEnabled = true;
float shadowDistance_ = 300.0f; // Shadow frustum half-extent (default: 300 units)
uint32_t shadowFrameCounter_ = 0;
public:
// Character preview registration (for off-screen composite pass)
void registerPreview(CharacterPreview* preview);
void unregisterPreview(CharacterPreview* preview);
void setShadowsEnabled(bool enabled) { shadowsEnabled = enabled; }
bool areShadowsEnabled() const { return shadowsEnabled; }
void setShadowDistance(float dist) { shadowDistance_ = glm::clamp(dist, 40.0f, 500.0f); }
float getShadowDistance() const { return shadowDistance_; }
void setMsaaSamples(VkSampleCountFlagBits samples);
// Post-process pipeline API — delegates to PostProcessPipeline (§4.3)
PostProcessPipeline* getPostProcessPipeline() const;
void setFXAAEnabled(bool enabled);
bool isFXAAEnabled() const;
void setFSREnabled(bool enabled);
bool isFSREnabled() const;
void setFSRQuality(float scaleFactor);
void setFSRSharpness(float sharpness);
float getFSRScaleFactor() const;
float getFSRSharpness() const;
void setFSR2Enabled(bool enabled);
bool isFSR2Enabled() const;
void setFSR2DebugTuning(float jitterSign, float motionVecScaleX, float motionVecScaleY);
void setAmdFsr3FramegenEnabled(bool enabled);
bool isAmdFsr3FramegenEnabled() const;
float getFSR2JitterSign() const;
float getFSR2MotionVecScaleX() const;
float getFSR2MotionVecScaleY() const;
bool isAmdFsr2SdkAvailable() const;
bool isAmdFsr3FramegenSdkAvailable() const;
bool isAmdFsr3FramegenRuntimeActive() const;
bool isAmdFsr3FramegenRuntimeReady() const;
const char* getAmdFsr3FramegenRuntimePath() const;
const std::string& getAmdFsr3FramegenRuntimeError() const;
size_t getAmdFsr3UpscaleDispatchCount() const;
size_t getAmdFsr3FramegenDispatchCount() const;
size_t getAmdFsr3FallbackCount() const;
void setBrightness(float b);
float getBrightness() const;
void setWaterRefractionEnabled(bool enabled);
bool isWaterRefractionEnabled() const;
private:
void applyMsaaChange();
VkSampleCountFlagBits pendingMsaaSamples_ = VK_SAMPLE_COUNT_1_BIT;
bool msaaChangePending_ = false;
void renderShadowPass();
glm::mat4 computeLightSpaceMatrix();
pipeline::AssetManager* cachedAssetManager = nullptr;
// Spell visual effects — owned SpellVisualSystem (extracted from Renderer §4.4)
std::unique_ptr<SpellVisualSystem> spellVisualSystem_;
// Post-process pipeline — owns all FSR/FXAA/FSR2 state (extracted §4.3)
std::unique_ptr<PostProcessPipeline> postProcessPipeline_;
uint32_t currentZoneId = 0;
std::string currentZoneName;
bool inTavern_ = false;
bool inBlacksmith_ = false;
bool playerIndoors_ = false; // Cached WMO inside state for macro conditionals
float musicSwitchCooldown_ = 0.0f;
bool deferredWorldInitEnabled_ = true;
bool deferredWorldInitPending_ = false;
uint8_t deferredWorldInitStage_ = 0;
float deferredWorldInitCooldown_ = 0.0f;
// Third-person character state
glm::vec3 characterPosition = glm::vec3(0.0f);
uint32_t characterInstanceId = 0;
float characterYaw = 0.0f;
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
// Selection circle rendering (Vulkan)
VkPipeline selCirclePipeline = VK_NULL_HANDLE;
VkPipelineLayout selCirclePipelineLayout = VK_NULL_HANDLE;
::VkBuffer selCircleVertBuf = VK_NULL_HANDLE;
VmaAllocation selCircleVertAlloc = VK_NULL_HANDLE;
::VkBuffer selCircleIdxBuf = VK_NULL_HANDLE;
VmaAllocation selCircleIdxAlloc = VK_NULL_HANDLE;
int selCircleVertCount = 0;
void initSelectionCircle();
void renderSelectionCircle(const glm::mat4& view, const glm::mat4& projection, VkCommandBuffer overrideCmd = VK_NULL_HANDLE);
glm::vec3 selCirclePos{0.0f};
glm::vec3 selCircleColor{1.0f, 0.0f, 0.0f};
float selCircleRadius = 1.5f;
bool selCircleVisible = false;
// Fullscreen color overlay (underwater tint)
VkPipeline overlayPipeline = VK_NULL_HANDLE;
VkPipelineLayout overlayPipelineLayout = VK_NULL_HANDLE;
void initOverlayPipeline();
void renderOverlay(const glm::vec4& color, VkCommandBuffer overrideCmd = VK_NULL_HANDLE);
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
// Vulkan frame state
VkContext* vkCtx = nullptr;
VkCommandBuffer currentCmd = VK_NULL_HANDLE;
uint32_t currentImageIndex = 0;
// Per-frame UBO + descriptors (set 0)
static constexpr uint32_t MAX_FRAMES = 2;
VkDescriptorSetLayout perFrameSetLayout = VK_NULL_HANDLE;
VkDescriptorPool sceneDescriptorPool = VK_NULL_HANDLE;
VkDescriptorSet perFrameDescSets[MAX_FRAMES] = {};
VkBuffer perFrameUBOs[MAX_FRAMES] = {};
VmaAllocation perFrameUBOAllocs[MAX_FRAMES] = {};
void* perFrameUBOMapped[MAX_FRAMES] = {};
GPUPerFrameData currentFrameData{};
float globalTime = 0.0f;
// Per-frame reflection UBO (mirrors camera for planar reflections)
VkBuffer reflPerFrameUBO = VK_NULL_HANDLE;
VmaAllocation reflPerFrameUBOAlloc = VK_NULL_HANDLE;
void* reflPerFrameUBOMapped = nullptr;
feat(animation): 452 named constants, 30-phase character animation state machine Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND, anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1) lookup, and flyVariant() compact 218-element ground→FLY_* resolver. Expand AnimationController into a full state machine with 20+ named states: spell cast (directed→omni→cast fallback chain, instant one-shot release), hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle, stealth animation substitution, loot, fishing channel, sit/sleep/kneel down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons (BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY, vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS), emote state variants, off-hand/pierce/dual-wield alternation, NPC birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell. Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo (12 constants) namespaces; replace all magic numbers in spell_handler.cpp. Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire GameObjectStateCallback. Add DBC cross-validation on world entry. Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and asset_pipeline_gui.py. Add tests/test_animation_ids.cpp. Bug fixes included: - Stand state 1 was animating READY_2H(27) — fixed to SITTING(97) - Spell casts ended freeze-frame — add one-shot release animation - NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff) - Chair sits (states 2/4/5/6) incorrectly played floor-sit transition - STOP(3) used for all spell casts — replaced with model-aware chain
2026-04-04 23:02:53 +03:00
VkDescriptorSet reflPerFrameDescSet[MAX_FRAMES] = {};
bool createPerFrameResources();
void destroyPerFrameResources();
void updatePerFrameUBO();
void setupWater1xPass();
void renderReflectionPass();
// ── Multithreaded secondary command buffer recording ──
// Indices into secondaryCmds_ arrays
static constexpr uint32_t SEC_SKY = 0; // sky (main thread)
static constexpr uint32_t SEC_TERRAIN = 1; // terrain (worker 0)
static constexpr uint32_t SEC_WMO = 2; // WMO (worker 1)
static constexpr uint32_t SEC_CHARS = 3; // selection circle + characters (main thread)
static constexpr uint32_t SEC_M2 = 4; // M2 + particles + glow (worker 2)
static constexpr uint32_t SEC_POST = 5; // water + weather + effects (main thread)
static constexpr uint32_t SEC_IMGUI = 6; // ImGui (main thread, non-FSR only)
static constexpr uint32_t NUM_SECONDARIES = 7;
static constexpr uint32_t NUM_WORKERS = 3; // terrain, WMO, M2
// Per-worker command pools (thread-safe: one pool per thread)
VkCommandPool workerCmdPools_[NUM_WORKERS] = {};
// Main-thread command pool for its secondary buffers
VkCommandPool mainSecondaryCmdPool_ = VK_NULL_HANDLE;
// Pre-allocated secondary command buffers [secondaryIndex][frameInFlight]
VkCommandBuffer secondaryCmds_[NUM_SECONDARIES][MAX_FRAMES] = {};
bool parallelRecordingEnabled_ = false; // set true after pools/buffers created
bool endFrameInlineMode_ = false; // true when endFrame switched to INLINE render pass
chore(renderer): extract AnimationController and remove audio pass-throughs Extract ~1,500 lines of character animation state from Renderer into a dedicated AnimationController class, and complete the AudioCoordinator migration by removing all 10 audio pass-through getters from Renderer. AnimationController: - New: include/rendering/animation_controller.hpp (182 lines) - New: src/rendering/animation_controller.cpp (1,703 lines) - Moves: locomotion state machine (50+ members), mount animation (40+ members), emote system, footstep triggering, surface detection, melee combat animations - Renderer holds std::unique_ptr<AnimationController> and delegates completely - AnimationController accesses audio via renderer_->getAudioCoordinator() Audio caller migration: - Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator directly, grouped by access pattern: - UIServices: settings_panel, game_screen, toast_manager, chat_panel, combat_ui, window_manager - GameServices: game_handler, spell_handler, inventory_handler, quest_handler, social_handler, combat_handler - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp - Remove 10 pass-through getter definitions from renderer.cpp - Remove 10 pass-through getter declarations from renderer.hpp - Remove individual audio manager forward declarations from renderer.hpp - Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly - game_handler.cpp: withSoundManager template uses services_.audioCoordinator; MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager - GameServices struct: add AudioCoordinator* audioCoordinator member - settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
float lastDeltaTime_ = 0.0f; // cached for post-process pipeline
bool createSecondaryCommandResources();
void destroySecondaryCommandResources();
VkCommandBuffer beginSecondary(uint32_t secondaryIndex);
void setSecondaryViewportScissor(VkCommandBuffer cmd);
// Cached render pass state for secondary buffer inheritance
VkRenderPass activeRenderPass_ = VK_NULL_HANDLE;
VkFramebuffer activeFramebuffer_ = VK_NULL_HANDLE;
VkExtent2D activeRenderExtent_ = {0, 0};
// Active character previews for off-screen rendering
std::vector<CharacterPreview*> activePreviews_;
bool terrainEnabled = true;
bool terrainLoaded = false;
bool ghostMode_ = false; // set each frame from gameHandler->isPlayerGhost()
feat(animation): 452 named constants, 30-phase character animation state machine Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND, anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1) lookup, and flyVariant() compact 218-element ground→FLY_* resolver. Expand AnimationController into a full state machine with 20+ named states: spell cast (directed→omni→cast fallback chain, instant one-shot release), hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle, stealth animation substitution, loot, fishing channel, sit/sleep/kneel down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons (BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY, vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS), emote state variants, off-hand/pierce/dual-wield alternation, NPC birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell. Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo (12 constants) namespaces; replace all magic numbers in spell_handler.cpp. Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire GameObjectStateCallback. Add DBC cross-validation on world entry. Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and asset_pipeline_gui.py. Add tests/test_animation_ids.cpp. Bug fixes included: - Stand state 1 was animating READY_2H(27) — fixed to SITTING(97) - Spell casts ended freeze-frame — add one-shot release animation - NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff) - Chair sits (states 2/4/5/6) incorrectly played floor-sit transition - STOP(3) used for all spell casts — replaced with model-aware chain
2026-04-04 23:02:53 +03:00
// Render Graph — declarative pass ordering with automatic barriers
feat(rendering): GPU architecture + visual quality fixes M2 GPU instancing - M2InstanceGPU SSBO (96 B/entry, double-buffered, 16384 max) - Group opaque instances by (modelId, LOD); single vkCmdDrawIndexed per group - boneBase field indexes into mega bone SSBO via gl_InstanceIndex Indirect terrain drawing - 24 MB mega index buffer (6M uint32) + 64 MB mega vertex buffer - CPU builds VkDrawIndexedIndirectCommand per visible chunk - Single VB/IB bind per frame; shadow pass reuses mega buffers - Replaced vkCmdDrawIndexedIndirect with direct vkCmdDrawIndexed to fix host-mapped buffer race condition that caused terrain flickering GPU frustum culling (compute shader) - m2_cull.comp.glsl: 64-thread workgroups, sphere-vs-6-planes + distance cull - CullInstanceGPU SSBO input, uint visibility[] output, double-buffered - dispatchCullCompute() runs before main pass via render graph node Consolidated bone matrix SSBOs - 16 MB double-buffered mega bone SSBO (2048 instances × 128 bones) - Eliminated per-instance descriptor sets; one megaBoneSet_ per frame - prepareRender() packs bone matrices consecutively into current frame slot Render graph / frame graph - RenderGraph: RGResource handles, RGPass nodes, Kahn topological sort - Automatic VkImageMemoryBarrier/VkBufferMemoryBarrier between passes - Passes: minimap_composite, worldmap_composite, preview_composite, shadow_pass, reflection_pass, compute_cull - beginFrame() uses buildFrameGraph() + renderGraph_->execute(cmd) Pipeline derivatives - PipelineBuilder::setFlags/setBasePipeline for VK_PIPELINE_CREATE_DERIVATIVE_BIT - M2 opaque = base; alphaTest/alpha/additive are derivatives - Applied to terrain (wireframe) and WMO (alpha-test) renderers Rendering bug fixes: - fix(shadow): compute lightSpaceMatrix before updatePerFrameUBO to eliminate one-frame lag that caused shadow trails and flicker on moving objects - fix(shadow): scale depth bias with shadowDistance_ instead of hardcoded 0.8f to prevent acne at close range and gaps at far range - fix(visibility): WMO group distance threshold 500u → 1200u to match terrain view distance; buildings were disappearing on the horizon - fix(precision): camera near plane 0.05 → 0.5 (ratio 600K:1 → 60K:1), eliminating Z-fighting and improving frustum plane extraction stability - fix(streaming): terrain load radius 4 → 6 tiles (~2133u → ~3200u) to exceed M2 render distance (2800u) and eliminate pop-in when camera turns; unload radius 7 → 9; spawn radius 3 → 4 - fix(visibility): ground-detail M2 distance multiplier 0.75 → 0.9 to reduce early pop of grass and debris
2026-04-04 13:43:16 +03:00
std::unique_ptr<RenderGraph> renderGraph_;
void buildFrameGraph(game::GameHandler* gameHandler);
// CPU timing stats (last frame/update).
double lastUpdateMs = 0.0;
double lastRenderMs = 0.0;
double lastCameraUpdateMs = 0.0;
double lastTerrainRenderMs = 0.0;
double lastWMORenderMs = 0.0;
double lastM2RenderMs = 0.0;
};
} // namespace rendering
} // namespace wowee