Browse Source

cleanup render utils

djeada 1 month ago
parent
commit
db4afea64e
100 changed files with 689 additions and 636 deletions
  1. 1 1
      Makefile
  2. 1 1
      app/controllers/action_vfx.cpp
  3. 3 3
      app/controllers/action_vfx.h
  4. 1 1
      app/controllers/command_controller.cpp
  5. 4 4
      app/controllers/command_controller.h
  6. 7 7
      app/core/game_engine.h
  7. 2 2
      app/models/audio_system_proxy.cpp
  8. 2 2
      app/models/audio_system_proxy.h
  9. 1 1
      app/models/cursor_mode.h
  10. 3 3
      app/models/hover_tracker.h
  11. 2 2
      app/utils/engine_view_helpers.h
  12. 2 2
      app/utils/json_vec_utils.cpp
  13. 2 2
      app/utils/json_vec_utils.h
  14. 2 2
      app/utils/movement_utils.h
  15. 2 2
      app/utils/selection_utils.h
  16. 47 51
      game/audio/AudioSystem.cpp
  17. 8 6
      game/audio/AudioSystem.h
  18. 132 89
      game/audio/MiniaudioBackend.cpp
  19. 24 30
      game/audio/MiniaudioBackend.h
  20. 38 33
      game/audio/Music.cpp
  21. 1 1
      game/audio/Music.h
  22. 125 62
      game/audio/MusicPlayer.cpp
  23. 19 25
      game/audio/MusicPlayer.h
  24. 18 36
      game/audio/Sound.cpp
  25. 5 4
      game/audio/Sound.h
  26. 3 2
      game/core/component.h
  27. 49 49
      game/core/serialization.cpp
  28. 5 4
      game/core/serialization.h
  29. 2 1
      game/map/level_loader.cpp
  30. 6 6
      game/map/terrain.cpp
  31. 1 2
      game/map/terrain_service.cpp
  32. 4 4
      game/units/factory.cpp
  33. 2 1
      game/units/spearman.cpp
  34. 2 2
      render/draw_queue.h
  35. 1 1
      render/draw_queue_soa.h
  36. 3 5
      render/entity/archer_renderer.cpp
  37. 1 1
      render/entity/arrow_vfx_renderer.cpp
  38. 3 3
      render/entity/arrow_vfx_renderer.h
  39. 2 2
      render/entity/barracks_renderer.cpp
  40. 1 1
      render/entity/barracks_renderer.h
  41. 2 2
      render/entity/horse_renderer.cpp
  42. 1 1
      render/entity/horse_renderer.h
  43. 3 5
      render/entity/knight_renderer.cpp
  44. 4 38
      render/entity/mounted_knight_renderer.cpp
  45. 1 1
      render/entity/registry.cpp
  46. 5 5
      render/entity/registry.h
  47. 30 0
      render/entity/renderer_constants.h
  48. 4 30
      render/entity/spearman_renderer.cpp
  49. 3 3
      render/geom/arrow.cpp
  50. 5 5
      render/geom/arrow.h
  51. 2 2
      render/geom/flag.cpp
  52. 2 2
      render/geom/flag.h
  53. 15 11
      render/geom/math_utils.h
  54. 1 1
      render/geom/patrol_flags.cpp
  55. 1 1
      render/geom/patrol_flags.h
  56. 1 1
      render/geom/selection_disc.cpp
  57. 1 1
      render/geom/selection_disc.h
  58. 1 1
      render/geom/selection_ring.cpp
  59. 1 1
      render/geom/selection_ring.h
  60. 2 2
      render/geom/transforms.cpp
  61. 1 1
      render/geom/transforms.h
  62. 1 1
      render/gl/backend.cpp
  63. 1 1
      render/gl/backend.h
  64. 2 2
      render/gl/bootstrap.cpp
  65. 2 2
      render/gl/bootstrap.h
  66. 1 1
      render/gl/buffer.cpp
  67. 1 1
      render/gl/buffer.h
  68. 13 13
      render/gl/camera.cpp
  69. 1 1
      render/gl/camera.h
  70. 1 1
      render/gl/mesh.cpp
  71. 1 1
      render/gl/mesh.h
  72. 1 1
      render/gl/persistent_buffer.h
  73. 2 2
      render/gl/primitives.cpp
  74. 1 1
      render/gl/primitives.h
  75. 1 1
      render/gl/resources.cpp
  76. 1 1
      render/gl/resources.h
  77. 1 1
      render/gl/shader.cpp
  78. 1 1
      render/gl/shader.h
  79. 1 1
      render/gl/shader_cache.h
  80. 1 1
      render/gl/state_scopes.h
  81. 1 1
      render/gl/texture.cpp
  82. 1 1
      render/gl/texture.h
  83. 2 2
      render/ground/biome_renderer.cpp
  84. 2 2
      render/ground/biome_renderer.h
  85. 1 1
      render/ground/bridge_renderer.cpp
  86. 2 2
      render/ground/bridge_renderer.h
  87. 1 1
      render/ground/fog_renderer.cpp
  88. 2 2
      render/ground/fog_renderer.h
  89. 1 1
      render/ground/grass_gpu.h
  90. 3 3
      render/ground/ground_renderer.cpp
  91. 2 2
      render/ground/ground_renderer.h
  92. 1 1
      render/ground/pine_gpu.h
  93. 2 2
      render/ground/pine_renderer.cpp
  94. 2 2
      render/ground/pine_renderer.h
  95. 1 1
      render/ground/plant_gpu.h
  96. 2 2
      render/ground/plant_renderer.cpp
  97. 2 2
      render/ground/plant_renderer.h
  98. 1 1
      render/ground/river_renderer.cpp
  99. 2 2
      render/ground/river_renderer.h
  100. 1 1
      render/ground/riverbank_asset_gpu.h

+ 1 - 1
Makefile

@@ -160,7 +160,7 @@ format:
 	fi
 	fi
 	@echo "$(BOLD)$(BLUE)Formatting C/C++ files with clang-format...$(RESET)"
 	@echo "$(BOLD)$(BLUE)Formatting C/C++ files with clang-format...$(RESET)"
 	@if command -v $(CLANG_FORMAT) >/dev/null 2>&1; then \
 	@if command -v $(CLANG_FORMAT) >/dev/null 2>&1; then \
-		find . -type f \( $(FMT_GLOBS) \) -not -path "./$(BUILD_DIR)/*" -print0 \
+		find . -type f \( $(FMT_GLOBS) \) -not -path "./$(BUILD_DIR)/* ./third_party/*" -print0 \
 		| xargs -0 -r $(CLANG_FORMAT) -i --style=file; \
 		| xargs -0 -r $(CLANG_FORMAT) -i --style=file; \
 		echo "$(GREEN)✓ C/C++ formatting complete$(RESET)"; \
 		echo "$(GREEN)✓ C/C++ formatting complete$(RESET)"; \
 	else \
 	else \

+ 1 - 1
app/controllers/action_vfx.cpp

@@ -33,4 +33,4 @@ void ActionVFX::spawnAttackArrow(Engine::Core::World *world,
                           Game::GameConfig::instance().arrow().speedAttack);
                           Game::GameConfig::instance().arrow().speedAttack);
 }
 }
 
 
-} // namespace App::Controllers
+} 

+ 3 - 3
app/controllers/action_vfx.h

@@ -6,8 +6,8 @@ namespace Engine {
 namespace Core {
 namespace Core {
 class World;
 class World;
 using EntityID = unsigned int;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} 
+} 
 
 
 namespace App::Controllers {
 namespace App::Controllers {
 
 
@@ -17,4 +17,4 @@ public:
                                Engine::Core::EntityID targetId);
                                Engine::Core::EntityID targetId);
 };
 };
 
 
-} // namespace App::Controllers
+} 

+ 1 - 1
app/controllers/command_controller.cpp

@@ -298,4 +298,4 @@ bool CommandController::anySelectedInHoldMode() const {
   return false;
   return false;
 }
 }
 
 
-} // namespace App::Controllers
+} 

+ 4 - 4
app/controllers/command_controller.h

@@ -10,13 +10,13 @@ namespace Core {
 class World;
 class World;
 class Entity;
 class Entity;
 using EntityID = unsigned int;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} 
+} 
 
 
 namespace Game::Systems {
 namespace Game::Systems {
 class SelectionSystem;
 class SelectionSystem;
 class PickingService;
 class PickingService;
-} // namespace Game::Systems
+} 
 
 
 namespace App::Controllers {
 namespace App::Controllers {
 
 
@@ -66,4 +66,4 @@ private:
   void resetMovement(Engine::Core::Entity *entity);
   void resetMovement(Engine::Core::Entity *entity);
 };
 };
 
 
-} // namespace App::Controllers
+} 

+ 7 - 7
app/core/game_engine.h

@@ -29,8 +29,8 @@ using EntityID = unsigned int;
 struct MovementComponent;
 struct MovementComponent;
 struct TransformComponent;
 struct TransformComponent;
 struct RenderableComponent;
 struct RenderableComponent;
-} // namespace Core
-} // namespace Engine
+} 
+} 
 
 
 namespace Render {
 namespace Render {
 namespace GL {
 namespace GL {
@@ -48,8 +48,8 @@ class StoneRenderer;
 class PlantRenderer;
 class PlantRenderer;
 class PineRenderer;
 class PineRenderer;
 struct IRenderPass;
 struct IRenderPass;
-} // namespace GL
-} // namespace Render
+} 
+} 
 
 
 namespace Game {
 namespace Game {
 namespace Systems {
 namespace Systems {
@@ -60,11 +60,11 @@ class PickingService;
 class VictoryService;
 class VictoryService;
 class CameraService;
 class CameraService;
 class SaveLoadService;
 class SaveLoadService;
-} // namespace Systems
+} 
 namespace Map {
 namespace Map {
 class MapCatalog;
 class MapCatalog;
 }
 }
-} // namespace Game
+} 
 
 
 namespace App {
 namespace App {
 namespace Controllers {
 namespace Controllers {
@@ -73,7 +73,7 @@ class CommandController;
 namespace Models {
 namespace Models {
 class AudioSystemProxy;
 class AudioSystemProxy;
 }
 }
-} // namespace App
+} 
 
 
 class QQuickWindow;
 class QQuickWindow;
 
 

+ 2 - 2
app/models/audio_system_proxy.cpp

@@ -38,5 +38,5 @@ float AudioSystemProxy::getVoiceVolume() const {
   return AudioSystem::getInstance().getVoiceVolume();
   return AudioSystem::getInstance().getVoiceVolume();
 }
 }
 
 
-} // namespace Models
-} // namespace App
+} 
+} 

+ 2 - 2
app/models/audio_system_proxy.h

@@ -22,5 +22,5 @@ public:
   Q_INVOKABLE float getVoiceVolume() const;
   Q_INVOKABLE float getVoiceVolume() const;
 };
 };
 
 
-} // namespace Models
-} // namespace App
+} 
+} 

+ 1 - 1
app/models/cursor_mode.h

@@ -41,4 +41,4 @@ inline CursorMode fromInt(int value) {
   }
   }
 }
 }
 
 
-} // namespace CursorModeUtils
+} 

+ 3 - 3
app/models/hover_tracker.h

@@ -7,14 +7,14 @@ namespace Engine {
 namespace Core {
 namespace Core {
 class World;
 class World;
 using EntityID = unsigned int;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} 
+} 
 
 
 namespace Render {
 namespace Render {
 namespace GL {
 namespace GL {
 class Camera;
 class Camera;
 }
 }
-} // namespace Render
+} 
 
 
 class HoverTracker {
 class HoverTracker {
 public:
 public:

+ 2 - 2
app/utils/engine_view_helpers.h

@@ -33,5 +33,5 @@ inline bool worldToScreen(const Game::Systems::PickingService *pickingService,
   return pickingService->worldToScreen(*camera, w, h, world, outScreen);
   return pickingService->worldToScreen(*camera, w, h, world, outScreen);
 }
 }
 
 
-} // namespace Utils
-} // namespace App
+} 
+} 

+ 2 - 2
app/utils/json_vec_utils.cpp

@@ -24,5 +24,5 @@ QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback) {
                    static_cast<float>(arr.at(2).toDouble(fallback.z())));
                    static_cast<float>(arr.at(2).toDouble(fallback.z())));
 }
 }
 
 
-} // namespace JsonUtils
-} // namespace App
+} 
+} 

+ 2 - 2
app/utils/json_vec_utils.h

@@ -11,5 +11,5 @@ QJsonArray vec3ToJsonArray(const QVector3D &vec);
 
 
 QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback);
 QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback);
 
 
-} // namespace JsonUtils
-} // namespace App
+} 
+} 

+ 2 - 2
app/utils/movement_utils.h

@@ -33,5 +33,5 @@ inline void resetMovement(Engine::Core::Entity *entity) {
   }
   }
 }
 }
 
 
-} // namespace Utils
-} // namespace App
+} 
+} 

+ 2 - 2
app/utils/selection_utils.h

@@ -33,5 +33,5 @@ inline void sanitizeSelection(Engine::Core::World *world,
   }
   }
 }
 }
 
 
-} // namespace Utils
-} // namespace App
+} 
+} 

+ 47 - 51
game/audio/AudioSystem.cpp

@@ -1,13 +1,14 @@
 #include "AudioSystem.h"
 #include "AudioSystem.h"
+#include "MiniaudioBackend.h"
 #include "MusicPlayer.h"
 #include "MusicPlayer.h"
 #include "Sound.h"
 #include "Sound.h"
-#include "MiniaudioBackend.h"
 #include <QDebug>
 #include <QDebug>
 #include <algorithm>
 #include <algorithm>
 
 
 AudioSystem::AudioSystem()
 AudioSystem::AudioSystem()
     : isRunning(false), masterVolume(1.0f), soundVolume(1.0f),
     : isRunning(false), masterVolume(1.0f), soundVolume(1.0f),
-      musicVolume(1.0f), voiceVolume(1.0f), maxChannels(32), m_musicPlayer(nullptr) {}
+      musicVolume(1.0f), voiceVolume(1.0f), maxChannels(32),
+      m_musicPlayer(nullptr) {}
 
 
 AudioSystem::~AudioSystem() { shutdown(); }
 AudioSystem::~AudioSystem() { shutdown(); }
 
 
@@ -21,7 +22,6 @@ bool AudioSystem::initialize() {
     return true;
     return true;
   }
   }
 
 
-  // Initialize the singleton music player
   m_musicPlayer = &Game::Audio::MusicPlayer::getInstance();
   m_musicPlayer = &Game::Audio::MusicPlayer::getInstance();
   if (!m_musicPlayer->initialize()) {
   if (!m_musicPlayer->initialize()) {
     qWarning() << "Failed to initialize MusicPlayer";
     qWarning() << "Failed to initialize MusicPlayer";
@@ -49,7 +49,6 @@ void AudioSystem::shutdown() {
     audioThread.join();
     audioThread.join();
   }
   }
 
 
-  // Shutdown music player
   if (m_musicPlayer) {
   if (m_musicPlayer) {
     m_musicPlayer->shutdown();
     m_musicPlayer->shutdown();
     m_musicPlayer = nullptr;
     m_musicPlayer = nullptr;
@@ -69,7 +68,7 @@ void AudioSystem::playSound(const std::string &soundId, float volume, bool loop,
                             int priority, AudioCategory category) {
                             int priority, AudioCategory category) {
   std::lock_guard<std::mutex> lock(queueMutex);
   std::lock_guard<std::mutex> lock(queueMutex);
   eventQueue.push(AudioEvent(AudioEventType::PLAY_SOUND, soundId, volume, loop,
   eventQueue.push(AudioEvent(AudioEventType::PLAY_SOUND, soundId, volume, loop,
-                              priority, category));
+                             priority, category));
   queueCondition.notify_one();
   queueCondition.notify_one();
 }
 }
 
 
@@ -102,7 +101,7 @@ void AudioSystem::setMasterVolume(float volume) {
         (it != soundCategories.end()) ? it->second : AudioCategory::SFX;
         (it != soundCategories.end()) ? it->second : AudioCategory::SFX;
     sound.second->setVolume(getEffectiveVolume(category, 1.0f));
     sound.second->setVolume(getEffectiveVolume(category, 1.0f));
   }
   }
-  // Update music player volume
+
   if (m_musicPlayer) {
   if (m_musicPlayer) {
     m_musicPlayer->setVolume(masterVolume * musicVolume);
     m_musicPlayer->setVolume(masterVolume * musicVolume);
   }
   }
@@ -161,8 +160,8 @@ bool AudioSystem::loadSound(const std::string &soundId,
     return true;
     return true;
   }
   }
 
 
-  // Get backend from MusicPlayer for sound effects
-  MiniaudioBackend* backend = m_musicPlayer ? m_musicPlayer->getBackend() : nullptr;
+  MiniaudioBackend *backend =
+      m_musicPlayer ? m_musicPlayer->getBackend() : nullptr;
   auto sound = std::make_unique<Sound>(filePath, backend);
   auto sound = std::make_unique<Sound>(filePath, backend);
   if (!sound || !sound->isLoaded()) {
   if (!sound || !sound->isLoaded()) {
     return false;
     return false;
@@ -177,13 +176,12 @@ bool AudioSystem::loadSound(const std::string &soundId,
 bool AudioSystem::loadMusic(const std::string &musicId,
 bool AudioSystem::loadMusic(const std::string &musicId,
                             const std::string &filePath) {
                             const std::string &filePath) {
   std::lock_guard<std::mutex> lock(resourceMutex);
   std::lock_guard<std::mutex> lock(resourceMutex);
-  
+
   if (!m_musicPlayer) {
   if (!m_musicPlayer) {
     qWarning() << "MusicPlayer not initialized";
     qWarning() << "MusicPlayer not initialized";
     return false;
     return false;
   }
   }
 
 
-  // Register the track with the music player
   m_musicPlayer->registerTrack(musicId, filePath);
   m_musicPlayer->registerTrack(musicId, filePath);
   activeResources.insert(musicId);
   activeResources.insert(musicId);
   return true;
   return true;
@@ -211,19 +209,19 @@ void AudioSystem::unloadAllSounds() {
 
 
 void AudioSystem::unloadAllMusic() {
 void AudioSystem::unloadAllMusic() {
   std::lock_guard<std::mutex> lock(resourceMutex);
   std::lock_guard<std::mutex> lock(resourceMutex);
-  // Stop the music player and clear all registered tracks
+
   if (m_musicPlayer) {
   if (m_musicPlayer) {
     m_musicPlayer->stop();
     m_musicPlayer->stop();
   }
   }
-  // Clear music-related resources from active set
+
   std::vector<std::string> musicResources;
   std::vector<std::string> musicResources;
-  for (const auto& res : activeResources) {
-    // Heuristic: if it's not in sounds map, it's likely a music resource
+  for (const auto &res : activeResources) {
+
     if (sounds.find(res) == sounds.end()) {
     if (sounds.find(res) == sounds.end()) {
       musicResources.push_back(res);
       musicResources.push_back(res);
     }
     }
   }
   }
-  for (const auto& res : musicResources) {
+  for (const auto &res : musicResources) {
     activeResources.erase(res);
     activeResources.erase(res);
   }
   }
 }
 }
@@ -345,7 +343,6 @@ void AudioSystem::processEvent(const AudioEvent &event) {
       activeResources.erase(event.resourceId);
       activeResources.erase(event.resourceId);
     }
     }
 
 
-    // Music tracks are just registered IDs, nothing to unload from player
     activeResources.erase(event.resourceId);
     activeResources.erase(event.resourceId);
     break;
     break;
   }
   }
@@ -366,7 +363,7 @@ bool AudioSystem::canPlaySound(int priority) {
 
 
 void AudioSystem::evictLowestPrioritySound() {
 void AudioSystem::evictLowestPrioritySound() {
   std::string soundIdToStop;
   std::string soundIdToStop;
-  
+
   {
   {
     std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
     std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
 
 
@@ -374,21 +371,21 @@ void AudioSystem::evictLowestPrioritySound() {
       return;
       return;
     }
     }
 
 
-    auto lowestIt = std::min_element(
-        activeSounds.begin(), activeSounds.end(),
-        [](const ActiveSound &a, const ActiveSound &b) {
-          if (a.priority != b.priority) {
-            return a.priority < b.priority;
-          }
-          return a.startTime < b.startTime;
-        });
+    auto lowestIt =
+        std::min_element(activeSounds.begin(), activeSounds.end(),
+                         [](const ActiveSound &a, const ActiveSound &b) {
+                           if (a.priority != b.priority) {
+                             return a.priority < b.priority;
+                           }
+                           return a.startTime < b.startTime;
+                         });
 
 
     if (lowestIt != activeSounds.end()) {
     if (lowestIt != activeSounds.end()) {
       soundIdToStop = lowestIt->id;
       soundIdToStop = lowestIt->id;
       activeSounds.erase(lowestIt);
       activeSounds.erase(lowestIt);
     }
     }
   }
   }
-  
+
   if (!soundIdToStop.empty()) {
   if (!soundIdToStop.empty()) {
     std::lock_guard<std::mutex> resourceLock(resourceMutex);
     std::lock_guard<std::mutex> resourceLock(resourceMutex);
     auto it = sounds.find(soundIdToStop);
     auto it = sounds.find(soundIdToStop);
@@ -400,7 +397,7 @@ void AudioSystem::evictLowestPrioritySound() {
 
 
 void AudioSystem::evictLowestPrioritySoundLocked() {
 void AudioSystem::evictLowestPrioritySoundLocked() {
   std::string soundIdToStop;
   std::string soundIdToStop;
-  
+
   {
   {
     std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
     std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
 
 
@@ -408,21 +405,21 @@ void AudioSystem::evictLowestPrioritySoundLocked() {
       return;
       return;
     }
     }
 
 
-    auto lowestIt = std::min_element(
-        activeSounds.begin(), activeSounds.end(),
-        [](const ActiveSound &a, const ActiveSound &b) {
-          if (a.priority != b.priority) {
-            return a.priority < b.priority;
-          }
-          return a.startTime < b.startTime;
-        });
+    auto lowestIt =
+        std::min_element(activeSounds.begin(), activeSounds.end(),
+                         [](const ActiveSound &a, const ActiveSound &b) {
+                           if (a.priority != b.priority) {
+                             return a.priority < b.priority;
+                           }
+                           return a.startTime < b.startTime;
+                         });
 
 
     if (lowestIt != activeSounds.end()) {
     if (lowestIt != activeSounds.end()) {
       soundIdToStop = lowestIt->id;
       soundIdToStop = lowestIt->id;
       activeSounds.erase(lowestIt);
       activeSounds.erase(lowestIt);
     }
     }
   }
   }
-  
+
   if (!soundIdToStop.empty()) {
   if (!soundIdToStop.empty()) {
     auto it = sounds.find(soundIdToStop);
     auto it = sounds.find(soundIdToStop);
     if (it != sounds.end()) {
     if (it != sounds.end()) {
@@ -435,21 +432,20 @@ void AudioSystem::cleanupInactiveSounds() {
   std::lock_guard<std::mutex> resourceLock(resourceMutex);
   std::lock_guard<std::mutex> resourceLock(resourceMutex);
   std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
   std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
 
 
-  activeSounds.erase(
-      std::remove_if(activeSounds.begin(), activeSounds.end(),
-                     [this](const ActiveSound &as) {
-                       if (as.loop) {
-                         return false;
-                       }
-
-                       auto it = sounds.find(as.id);
-                       if (it == sounds.end()) {
-                         return true;
-                       }
-
-                       return false;
-                     }),
-      activeSounds.end());
+  activeSounds.erase(std::remove_if(activeSounds.begin(), activeSounds.end(),
+                                    [this](const ActiveSound &as) {
+                                      if (as.loop) {
+                                        return false;
+                                      }
+
+                                      auto it = sounds.find(as.id);
+                                      if (it == sounds.end()) {
+                                        return true;
+                                      }
+
+                                      return false;
+                                    }),
+                     activeSounds.end());
 }
 }
 
 
 float AudioSystem::getEffectiveVolume(AudioCategory category,
 float AudioSystem::getEffectiveVolume(AudioCategory category,

+ 8 - 6
game/audio/AudioSystem.h

@@ -13,7 +13,11 @@
 #include <vector>
 #include <vector>
 
 
 class Sound;
 class Sound;
-namespace Game { namespace Audio { class MusicPlayer; } }
+namespace Game {
+namespace Audio {
+class MusicPlayer;
+}
+} // namespace Game
 
 
 enum class AudioEventType {
 enum class AudioEventType {
   PLAY_SOUND,
   PLAY_SOUND,
@@ -39,8 +43,7 @@ struct AudioEvent {
   AudioCategory category = AudioCategory::SFX;
   AudioCategory category = AudioCategory::SFX;
 
 
   AudioEvent(AudioEventType t, const std::string &id = "", float vol = 1.0f,
   AudioEvent(AudioEventType t, const std::string &id = "", float vol = 1.0f,
-             bool l = false, int p = 0,
-             AudioCategory cat = AudioCategory::SFX)
+             bool l = false, int p = 0, AudioCategory cat = AudioCategory::SFX)
       : type(t), resourceId(id), volume(vol), loop(l), priority(p),
       : type(t), resourceId(id), volume(vol), loop(l), priority(p),
         category(cat) {}
         category(cat) {}
 };
 };
@@ -101,9 +104,8 @@ private:
   std::unordered_map<std::string, AudioCategory> soundCategories;
   std::unordered_map<std::string, AudioCategory> soundCategories;
   std::unordered_set<std::string> activeResources;
   std::unordered_set<std::string> activeResources;
   mutable std::mutex resourceMutex;
   mutable std::mutex resourceMutex;
-  
-  // Use singleton MusicPlayer instead of individual Music objects
-  Game::Audio::MusicPlayer* m_musicPlayer;
+
+  Game::Audio::MusicPlayer *m_musicPlayer;
 
 
   std::thread audioThread;
   std::thread audioThread;
   std::queue<AudioEvent> eventQueue;
   std::queue<AudioEvent> eventQueue;

+ 132 - 89
game/audio/MiniaudioBackend.cpp

@@ -1,68 +1,75 @@
 #include "MiniaudioBackend.h"
 #include "MiniaudioBackend.h"
 #include <QDebug>
 #include <QDebug>
-#include <cstring>
 #include <cmath>
 #include <cmath>
+#include <cstring>
 
 
-// =================== miniaudio ===================
 #define MINIAUDIO_IMPLEMENTATION
 #define MINIAUDIO_IMPLEMENTATION
 #define MA_NO_ENCODING
 #define MA_NO_ENCODING
 #define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
 #define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
-// Enable common backends (Pulse/ALSA/CoreAudio/WASAPI/JACK optional)
+
 #define MA_ENABLE_PULSEAUDIO
 #define MA_ENABLE_PULSEAUDIO
 #define MA_ENABLE_ALSA
 #define MA_ENABLE_ALSA
 #define MA_ENABLE_WASAPI
 #define MA_ENABLE_WASAPI
 #define MA_ENABLE_COREAUDIO
 #define MA_ENABLE_COREAUDIO
-// Decoders
+
 #define MA_ENABLE_MP3
 #define MA_ENABLE_MP3
 #define MA_ENABLE_FLAC
 #define MA_ENABLE_FLAC
 #define MA_ENABLE_VORBIS
 #define MA_ENABLE_VORBIS
 #include "third_party/miniaudio.h"
 #include "third_party/miniaudio.h"
-// ================================================
 
 
 struct DeviceWrapper {
 struct DeviceWrapper {
-  MiniaudioBackend* self;
+  MiniaudioBackend *self;
 };
 };
 
 
-// Static callback proxy
-static void audioCallback(ma_device* device, void* pOutput, const void*, ma_uint32 frameCount) {
-  auto* w = reinterpret_cast<DeviceWrapper*>(device->pUserData);
-  if (!w || !w->self) { std::memset(pOutput, 0, frameCount*2*sizeof(float)); return; }
-  w->self->onAudio(reinterpret_cast<float*>(pOutput), frameCount);
+static void audioCallback(ma_device *device, void *pOutput, const void *,
+                          ma_uint32 frameCount) {
+  auto *w = reinterpret_cast<DeviceWrapper *>(device->pUserData);
+  if (!w || !w->self) {
+    std::memset(pOutput, 0, frameCount * 2 * sizeof(float));
+    return;
+  }
+  w->self->onAudio(reinterpret_cast<float *>(pOutput), frameCount);
 }
 }
 
 
-MiniaudioBackend::MiniaudioBackend(QObject* parent) : QObject(parent) {}
+MiniaudioBackend::MiniaudioBackend(QObject *parent) : QObject(parent) {}
 MiniaudioBackend::~MiniaudioBackend() { shutdown(); }
 MiniaudioBackend::~MiniaudioBackend() { shutdown(); }
 
 
-bool MiniaudioBackend::initialize(int deviceRate, int outChannels, int musicChannels) {
-  m_rate  = std::max(22050, deviceRate);
-  m_outCh = 2; // we always mix to stereo
+bool MiniaudioBackend::initialize(int deviceRate, int outChannels,
+                                  int musicChannels) {
+  m_rate = std::max(22050, deviceRate);
+  m_outCh = 2;
 
 
-  // Create device (float32 stereo)
   ma_device_config cfg = ma_device_config_init(ma_device_type_playback);
   ma_device_config cfg = ma_device_config_init(ma_device_type_playback);
-  cfg.playback.format   = ma_format_f32;
+  cfg.playback.format = ma_format_f32;
   cfg.playback.channels = m_outCh;
   cfg.playback.channels = m_outCh;
-  cfg.sampleRate        = m_rate;
-  cfg.dataCallback      = audioCallback;
+  cfg.sampleRate = m_rate;
+  cfg.dataCallback = audioCallback;
 
 
-  auto* wrap = new DeviceWrapper{ this };
+  auto *wrap = new DeviceWrapper{this};
   cfg.pUserData = wrap;
   cfg.pUserData = wrap;
 
 
   m_device = new ma_device();
   m_device = new ma_device();
   if (ma_device_init(nullptr, &cfg, m_device) != MA_SUCCESS) {
   if (ma_device_init(nullptr, &cfg, m_device) != MA_SUCCESS) {
-    delete m_device; m_device = nullptr;
+    delete m_device;
+    m_device = nullptr;
     delete wrap;
     delete wrap;
     return false;
     return false;
   }
   }
 
 
   m_channels.resize(std::max(1, musicChannels));
   m_channels.resize(std::max(1, musicChannels));
-  for (auto& ch : m_channels) ch = Channel{};
+  for (auto &ch : m_channels)
+    ch = Channel{};
 
 
-  // Initialize sound effect slots (32 concurrent sounds)
   m_soundEffects.resize(32);
   m_soundEffects.resize(32);
-  for (auto& sfx : m_soundEffects) sfx = SoundEffect{};
+  for (auto &sfx : m_soundEffects)
+    sfx = SoundEffect{};
 
 
   if (ma_device_start(m_device) != MA_SUCCESS) {
   if (ma_device_start(m_device) != MA_SUCCESS) {
-    ma_device_uninit(m_device); delete m_device; m_device = nullptr; delete wrap; return false;
+    ma_device_uninit(m_device);
+    delete m_device;
+    m_device = nullptr;
+    delete wrap;
+    return false;
   }
   }
 
 
   return true;
   return true;
@@ -76,25 +83,28 @@ void MiniaudioBackend::shutdown() {
 }
 }
 
 
 void MiniaudioBackend::stopDevice() {
 void MiniaudioBackend::stopDevice() {
-  if (!m_device) return;
-  auto* wrap = reinterpret_cast<DeviceWrapper*>(m_device->pUserData);
+  if (!m_device)
+    return;
+  auto *wrap = reinterpret_cast<DeviceWrapper *>(m_device->pUserData);
   ma_device_stop(m_device);
   ma_device_stop(m_device);
   ma_device_uninit(m_device);
   ma_device_uninit(m_device);
-  delete m_device; m_device = nullptr;
+  delete m_device;
+  m_device = nullptr;
   delete wrap;
   delete wrap;
 }
 }
 
 
-bool MiniaudioBackend::predecode(const QString& id, const QString& path) {
-  // Decode the file into float32/stereo/m_rate using miniaudio's built-in converters.
+bool MiniaudioBackend::predecode(const QString &id, const QString &path) {
+
   ma_decoder_config dc = ma_decoder_config_init(ma_format_f32, m_outCh, m_rate);
   ma_decoder_config dc = ma_decoder_config_init(ma_format_f32, m_outCh, m_rate);
   ma_decoder dec;
   ma_decoder dec;
-  if (ma_decoder_init_file(path.toUtf8().constData(), &dc, &dec) != MA_SUCCESS) {
+  if (ma_decoder_init_file(path.toUtf8().constData(), &dc, &dec) !=
+      MA_SUCCESS) {
     qWarning() << "miniaudio: cannot open" << path;
     qWarning() << "miniaudio: cannot open" << path;
     return false;
     return false;
   }
   }
 
 
   QVector<float> pcm;
   QVector<float> pcm;
-  float buffer[4096 * 2]; // frames * channels (stereo)
+  float buffer[4096 * 2];
   for (;;) {
   for (;;) {
     ma_uint64 framesRead = 0;
     ma_uint64 framesRead = 0;
     ma_result r = ma_decoder_read_pcm_frames(&dec, buffer, 4096, &framesRead);
     ma_result r = ma_decoder_read_pcm_frames(&dec, buffer, 4096, &framesRead);
@@ -104,8 +114,12 @@ bool MiniaudioBackend::predecode(const QString& id, const QString& path) {
       pcm.resize(old + samples);
       pcm.resize(old + samples);
       std::memcpy(pcm.data() + old, buffer, samples * sizeof(float));
       std::memcpy(pcm.data() + old, buffer, samples * sizeof(float));
     }
     }
-    if (r == MA_AT_END) break;
-    if (r != MA_SUCCESS) { ma_decoder_uninit(&dec); return false; }
+    if (r == MA_AT_END)
+      break;
+    if (r != MA_SUCCESS) {
+      ma_decoder_uninit(&dec);
+      return false;
+    }
   }
   }
   ma_decoder_uninit(&dec);
   ma_decoder_uninit(&dec);
 
 
@@ -117,27 +131,32 @@ bool MiniaudioBackend::predecode(const QString& id, const QString& path) {
   return true;
   return true;
 }
 }
 
 
-void MiniaudioBackend::play(int channel, const QString& id, float volume, bool loop, int fadeMs) {
+void MiniaudioBackend::play(int channel, const QString &id, float volume,
+                            bool loop, int fadeMs) {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
-  if (channel < 0 || channel >= m_channels.size()) return;
+  if (channel < 0 || channel >= m_channels.size())
+    return;
   auto it = m_tracks.find(id);
   auto it = m_tracks.find(id);
   if (it == m_tracks.end()) {
   if (it == m_tracks.end()) {
     lk.unlock();
     lk.unlock();
-    // Lazy decode if not predecoded yet:
-    predecode(id, id); // NOTE: 'id' is not a path here; callers predecode on registerTrack.
+
+    predecode(id, id);
     lk.relock();
     lk.relock();
     it = m_tracks.find(id);
     it = m_tracks.find(id);
-    if (it == m_tracks.end()) { qWarning() << "MiniaudioBackend: unknown track" << id; return; }
+    if (it == m_tracks.end()) {
+      qWarning() << "MiniaudioBackend: unknown track" << id;
+      return;
+    }
   }
   }
 
 
-  auto& ch = m_channels[channel];
+  auto &ch = m_channels[channel];
   ch.track = &it.value();
   ch.track = &it.value();
   ch.framePos = 0;
   ch.framePos = 0;
   ch.looping = loop;
   ch.looping = loop;
-  ch.paused  = false;
-  ch.active  = true;
-  ch.tgtVol  = std::clamp(volume, 0.0f, 1.0f);
-  ch.curVol  = 0.0f;
+  ch.paused = false;
+  ch.active = true;
+  ch.tgtVol = std::clamp(volume, 0.0f, 1.0f);
+  ch.curVol = 0.0f;
 
 
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   ch.fadeSamples = fadeSamples;
   ch.fadeSamples = fadeSamples;
@@ -146,9 +165,11 @@ void MiniaudioBackend::play(int channel, const QString& id, float volume, bool l
 
 
 void MiniaudioBackend::stop(int channel, int fadeMs) {
 void MiniaudioBackend::stop(int channel, int fadeMs) {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
-  if (channel < 0 || channel >= m_channels.size()) return;
-  auto& ch = m_channels[channel];
-  if (!ch.active) return;
+  if (channel < 0 || channel >= m_channels.size())
+    return;
+  auto &ch = m_channels[channel];
+  if (!ch.active)
+    return;
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   ch.tgtVol = 0.0f;
   ch.tgtVol = 0.0f;
   ch.fadeSamples = fadeSamples;
   ch.fadeSamples = fadeSamples;
@@ -156,14 +177,24 @@ void MiniaudioBackend::stop(int channel, int fadeMs) {
   ch.looping = false;
   ch.looping = false;
 }
 }
 
 
-void MiniaudioBackend::pause(int channel)  { QMutexLocker lk(&m_mutex); if (channel >=0 && channel < m_channels.size()) m_channels[channel].paused = true; }
-void MiniaudioBackend::resume(int channel) { QMutexLocker lk(&m_mutex); if (channel >=0 && channel < m_channels.size()) m_channels[channel].paused = false; }
+void MiniaudioBackend::pause(int channel) {
+  QMutexLocker lk(&m_mutex);
+  if (channel >= 0 && channel < m_channels.size())
+    m_channels[channel].paused = true;
+}
+void MiniaudioBackend::resume(int channel) {
+  QMutexLocker lk(&m_mutex);
+  if (channel >= 0 && channel < m_channels.size())
+    m_channels[channel].paused = false;
+}
 
 
 void MiniaudioBackend::setVolume(int channel, float volume, int fadeMs) {
 void MiniaudioBackend::setVolume(int channel, float volume, int fadeMs) {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
-  if (channel < 0 || channel >= m_channels.size()) return;
-  auto& ch = m_channels[channel];
-  if (!ch.active) return;
+  if (channel < 0 || channel >= m_channels.size())
+    return;
+  auto &ch = m_channels[channel];
+  if (!ch.active)
+    return;
   ch.tgtVol = std::clamp(volume, 0.0f, 1.0f);
   ch.tgtVol = std::clamp(volume, 0.0f, 1.0f);
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   ch.fadeSamples = fadeSamples;
   ch.fadeSamples = fadeSamples;
@@ -173,8 +204,9 @@ void MiniaudioBackend::setVolume(int channel, float volume, int fadeMs) {
 void MiniaudioBackend::stopAll(int fadeMs) {
 void MiniaudioBackend::stopAll(int fadeMs) {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
   const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
-  for (auto& ch : m_channels) {
-    if (!ch.active) continue;
+  for (auto &ch : m_channels) {
+    if (!ch.active)
+      continue;
     ch.tgtVol = 0.0f;
     ch.tgtVol = 0.0f;
     ch.fadeSamples = fadeSamples;
     ch.fadeSamples = fadeSamples;
     ch.volStep = (ch.tgtVol - ch.curVol) / float(fadeSamples);
     ch.volStep = (ch.tgtVol - ch.curVol) / float(fadeSamples);
@@ -182,39 +214,42 @@ void MiniaudioBackend::stopAll(int fadeMs) {
   }
   }
 }
 }
 
 
-void MiniaudioBackend::setMasterVolume(float volume, int /*fadeMs*/) {
+void MiniaudioBackend::setMasterVolume(float volume, int) {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
   m_masterVol = std::clamp(volume, 0.0f, 1.0f);
   m_masterVol = std::clamp(volume, 0.0f, 1.0f);
 }
 }
 
 
 bool MiniaudioBackend::anyChannelPlaying() const {
 bool MiniaudioBackend::anyChannelPlaying() const {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
-  for (const auto& ch : m_channels) if (ch.active && !ch.paused) return true;
+  for (const auto &ch : m_channels)
+    if (ch.active && !ch.paused)
+      return true;
   return false;
   return false;
 }
 }
 bool MiniaudioBackend::channelPlaying(int channel) const {
 bool MiniaudioBackend::channelPlaying(int channel) const {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
-  if (channel < 0 || channel >= m_channels.size()) return false;
-  const auto& ch = m_channels[channel];
+  if (channel < 0 || channel >= m_channels.size())
+    return false;
+  const auto &ch = m_channels[channel];
   return ch.active && !ch.paused;
   return ch.active && !ch.paused;
 }
 }
 
 
-void MiniaudioBackend::playSound(const QString& id, float volume, bool loop) {
+void MiniaudioBackend::playSound(const QString &id, float volume, bool loop) {
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
-  
+
   auto it = m_tracks.find(id);
   auto it = m_tracks.find(id);
   if (it == m_tracks.end()) {
   if (it == m_tracks.end()) {
     qWarning() << "MiniaudioBackend: Sound not preloaded:" << id;
     qWarning() << "MiniaudioBackend: Sound not preloaded:" << id;
     return;
     return;
   }
   }
-  
+
   int slot = findFreeSoundSlot();
   int slot = findFreeSoundSlot();
   if (slot < 0) {
   if (slot < 0) {
     qWarning() << "MiniaudioBackend: No free sound slots available";
     qWarning() << "MiniaudioBackend: No free sound slots available";
     return;
     return;
   }
   }
-  
-  auto& sfx = m_soundEffects[slot];
+
+  auto &sfx = m_soundEffects[slot];
   sfx.track = &it.value();
   sfx.track = &it.value();
   sfx.framePos = 0;
   sfx.framePos = 0;
   sfx.volume = std::clamp(volume, 0.0f, 1.0f);
   sfx.volume = std::clamp(volume, 0.0f, 1.0f);
@@ -224,45 +259,51 @@ void MiniaudioBackend::playSound(const QString& id, float volume, bool loop) {
 
 
 int MiniaudioBackend::findFreeSoundSlot() const {
 int MiniaudioBackend::findFreeSoundSlot() const {
   for (int i = 0; i < m_soundEffects.size(); ++i) {
   for (int i = 0; i < m_soundEffects.size(); ++i) {
-    if (!m_soundEffects[i].active) return i;
+    if (!m_soundEffects[i].active)
+      return i;
   }
   }
   return -1;
   return -1;
 }
 }
 
 
-void MiniaudioBackend::onAudio(float* out, unsigned frames) {
-  // Zero output
+void MiniaudioBackend::onAudio(float *out, unsigned frames) {
+
   const unsigned samples = frames * 2;
   const unsigned samples = frames * 2;
   std::memset(out, 0, samples * sizeof(float));
   std::memset(out, 0, samples * sizeof(float));
 
 
   QMutexLocker lk(&m_mutex);
   QMutexLocker lk(&m_mutex);
 
 
-  for (auto& ch : m_channels) {
-    if (!ch.active || ch.paused || ch.track == nullptr) continue;
+  for (auto &ch : m_channels) {
+    if (!ch.active || ch.paused || ch.track == nullptr)
+      continue;
 
 
-    const auto* pcm = ch.track->pcm.constData();
+    const auto *pcm = ch.track->pcm.constData();
     unsigned framesLeft = frames;
     unsigned framesLeft = frames;
     unsigned pos = ch.framePos;
     unsigned pos = ch.framePos;
 
 
-    float* dst = out;
+    float *dst = out;
 
 
     while (framesLeft > 0) {
     while (framesLeft > 0) {
       if (pos >= ch.track->frames) {
       if (pos >= ch.track->frames) {
-        if (ch.looping) pos = 0;
-        else break;
+        if (ch.looping)
+          pos = 0;
+        else
+          break;
       }
       }
       const unsigned canCopy = std::min(framesLeft, ch.track->frames - pos);
       const unsigned canCopy = std::min(framesLeft, ch.track->frames - pos);
-      const float* src = pcm + pos * 2;
+      const float *src = pcm + pos * 2;
 
 
       for (unsigned i = 0; i < canCopy; ++i) {
       for (unsigned i = 0; i < canCopy; ++i) {
         const float vol = ch.curVol * m_masterVol;
         const float vol = ch.curVol * m_masterVol;
         dst[0] += src[0] * vol;
         dst[0] += src[0] * vol;
         dst[1] += src[1] * vol;
         dst[1] += src[1] * vol;
-        dst += 2; src += 2;
+        dst += 2;
+        src += 2;
 
 
         if (ch.fadeSamples > 0) {
         if (ch.fadeSamples > 0) {
           ch.curVol += ch.volStep;
           ch.curVol += ch.volStep;
           --ch.fadeSamples;
           --ch.fadeSamples;
-          if (ch.fadeSamples == 0) ch.curVol = ch.tgtVol;
+          if (ch.fadeSamples == 0)
+            ch.curVol = ch.tgtVol;
         }
         }
       }
       }
       pos += canCopy;
       pos += canCopy;
@@ -271,24 +312,25 @@ void MiniaudioBackend::onAudio(float* out, unsigned frames) {
 
 
     ch.framePos = pos;
     ch.framePos = pos;
 
 
-    // deactivate at end if not looping or after fade to 0
     if (!ch.looping && ch.framePos >= ch.track->frames) {
     if (!ch.looping && ch.framePos >= ch.track->frames) {
       ch.active = false;
       ch.active = false;
-      ch.curVol = ch.tgtVol = 0.0f; ch.fadeSamples = 0;
+      ch.curVol = ch.tgtVol = 0.0f;
+      ch.fadeSamples = 0;
     }
     }
-    if (ch.fadeSamples == 0 && ch.curVol == 0.0f && ch.tgtVol == 0.0f && !ch.looping) {
+    if (ch.fadeSamples == 0 && ch.curVol == 0.0f && ch.tgtVol == 0.0f &&
+        !ch.looping) {
       ch.active = false;
       ch.active = false;
     }
     }
   }
   }
 
 
-  // Mix sound effects
-  for (auto& sfx : m_soundEffects) {
-    if (!sfx.active || sfx.track == nullptr) continue;
+  for (auto &sfx : m_soundEffects) {
+    if (!sfx.active || sfx.track == nullptr)
+      continue;
 
 
-    const auto* pcm = sfx.track->pcm.constData();
+    const auto *pcm = sfx.track->pcm.constData();
     unsigned framesLeft = frames;
     unsigned framesLeft = frames;
     unsigned pos = sfx.framePos;
     unsigned pos = sfx.framePos;
-    float* dst = out;
+    float *dst = out;
 
 
     while (framesLeft > 0) {
     while (framesLeft > 0) {
       if (pos >= sfx.track->frames) {
       if (pos >= sfx.track->frames) {
@@ -299,9 +341,9 @@ void MiniaudioBackend::onAudio(float* out, unsigned frames) {
           break;
           break;
         }
         }
       }
       }
-      
+
       const unsigned canCopy = std::min(framesLeft, sfx.track->frames - pos);
       const unsigned canCopy = std::min(framesLeft, sfx.track->frames - pos);
-      const float* src = pcm + pos * 2;
+      const float *src = pcm + pos * 2;
 
 
       for (unsigned i = 0; i < canCopy; ++i) {
       for (unsigned i = 0; i < canCopy; ++i) {
         const float vol = sfx.volume * m_masterVol;
         const float vol = sfx.volume * m_masterVol;
@@ -310,7 +352,7 @@ void MiniaudioBackend::onAudio(float* out, unsigned frames) {
         dst += 2;
         dst += 2;
         src += 2;
         src += 2;
       }
       }
-      
+
       pos += canCopy;
       pos += canCopy;
       framesLeft -= canCopy;
       framesLeft -= canCopy;
     }
     }
@@ -318,9 +360,10 @@ void MiniaudioBackend::onAudio(float* out, unsigned frames) {
     sfx.framePos = pos;
     sfx.framePos = pos;
   }
   }
 
 
-  // clip
   for (unsigned i = 0; i < samples; ++i) {
   for (unsigned i = 0; i < samples; ++i) {
-    if (out[i] > 1.0f) out[i] = 1.0f;
-    else if (out[i] < -1.0f) out[i] = -1.0f;
+    if (out[i] > 1.0f)
+      out[i] = 1.0f;
+    else if (out[i] < -1.0f)
+      out[i] = -1.0f;
   }
   }
 }
 }

+ 24 - 30
game/audio/MiniaudioBackend.h

@@ -1,28 +1,26 @@
 #pragma once
 #pragma once
-#include <QObject>
-#include <QMutex>
 #include <QMap>
 #include <QMap>
-#include <QVector>
+#include <QMutex>
+#include <QObject>
 #include <QString>
 #include <QString>
+#include <QVector>
 #include <atomic>
 #include <atomic>
 
 
-// forward from miniaudio
 struct ma_device;
 struct ma_device;
 
 
 class MiniaudioBackend : public QObject {
 class MiniaudioBackend : public QObject {
   Q_OBJECT
   Q_OBJECT
 public:
 public:
-  explicit MiniaudioBackend(QObject* parent = nullptr);
+  explicit MiniaudioBackend(QObject *parent = nullptr);
   ~MiniaudioBackend() override;
   ~MiniaudioBackend() override;
 
 
   bool initialize(int deviceRate, int outChannels, int musicChannels);
   bool initialize(int deviceRate, int outChannels, int musicChannels);
   void shutdown();
   void shutdown();
 
 
-  // Pre-decode (float32/stereo/deviceRate)
-  bool predecode(const QString& id, const QString& path);
+  bool predecode(const QString &id, const QString &path);
 
 
-  // Playback control (thread-safe)
-  void play(int channel, const QString& id, float volume, bool loop, int fadeMs);
+  void play(int channel, const QString &id, float volume, bool loop,
+            int fadeMs);
   void stop(int channel, int fadeMs);
   void stop(int channel, int fadeMs);
   void pause(int channel);
   void pause(int channel);
   void resume(int channel);
   void resume(int channel);
@@ -33,32 +31,30 @@ public:
   bool anyChannelPlaying() const;
   bool anyChannelPlaying() const;
   bool channelPlaying(int channel) const;
   bool channelPlaying(int channel) const;
 
 
-  // Sound effects - one-shot playback
-  void playSound(const QString& id, float volume, bool loop = false);
+  void playSound(const QString &id, float volume, bool loop = false);
 
 
-  // Called by audio callback:
-  void onAudio(float* out, unsigned frames);
+  void onAudio(float *out, unsigned frames);
 
 
 private:
 private:
   struct DecodedTrack {
   struct DecodedTrack {
-    QVector<float> pcm; // interleaved stereo, f32, deviceRate
-    unsigned       frames = 0; // pcm.size()/2
+    QVector<float> pcm;
+    unsigned frames = 0;
   };
   };
 
 
   struct Channel {
   struct Channel {
-    const DecodedTrack* track = nullptr;
+    const DecodedTrack *track = nullptr;
     unsigned framePos = 0;
     unsigned framePos = 0;
     float curVol = 0.0f;
     float curVol = 0.0f;
     float tgtVol = 1.0f;
     float tgtVol = 1.0f;
     float volStep = 0.0f;
     float volStep = 0.0f;
     unsigned fadeSamples = 0;
     unsigned fadeSamples = 0;
-    bool   looping = false;
-    bool   paused  = false;
-    bool   active  = false;
+    bool looping = false;
+    bool paused = false;
+    bool active = false;
   };
   };
 
 
   struct SoundEffect {
   struct SoundEffect {
-    const DecodedTrack* track = nullptr;
+    const DecodedTrack *track = nullptr;
     unsigned framePos = 0;
     unsigned framePos = 0;
     float volume = 1.0f;
     float volume = 1.0f;
     bool looping = false;
     bool looping = false;
@@ -71,15 +67,13 @@ private:
   int findFreeSoundSlot() const;
   int findFreeSoundSlot() const;
 
 
 private:
 private:
-  // device
-  ma_device*        m_device {nullptr};
-  int               m_rate {48000};
-  int               m_outCh {2};
+  ma_device *m_device{nullptr};
+  int m_rate{48000};
+  int m_outCh{2};
 
 
-  // state
-  mutable QMutex    m_mutex;
-  QMap<QString, DecodedTrack> m_tracks; // id -> decoded PCM
-  QVector<Channel>  m_channels;
-  QVector<SoundEffect> m_soundEffects; // Fixed pool of sound effect slots
-  float             m_masterVol {1.0f};
+  mutable QMutex m_mutex;
+  QMap<QString, DecodedTrack> m_tracks;
+  QVector<Channel> m_channels;
+  QVector<SoundEffect> m_soundEffects;
+  float m_masterVol{1.0f};
 };
 };

+ 38 - 33
game/audio/Music.cpp

@@ -21,27 +21,33 @@ Music::Music(const std::string &filePath)
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
   audioOutput = new QAudioOutput(player);
   audioOutput = new QAudioOutput(player);
   player->setAudioOutput(audioOutput);
   player->setAudioOutput(audioOutput);
-  
-  // Add debugging signal connections
+
   QObject::connect(player, &QMediaPlayer::errorOccurred,
   QObject::connect(player, &QMediaPlayer::errorOccurred,
-                   [filepath = this->filepath](QMediaPlayer::Error error, const QString &desc) {
-                     qWarning() << "QMediaPlayer error for" << QString::fromStdString(filepath)
-                                << "- Error code:" << static_cast<int>(error) << "Message:" << desc;
-                   });
-  
-  QObject::connect(player, &QMediaPlayer::mediaStatusChanged,
-                   [filepath = this->filepath, this](QMediaPlayer::MediaStatus status) {
-                     qDebug() << "Media status for" << QString::fromStdString(filepath) << ":" << static_cast<int>(status);
-                     if (status == QMediaPlayer::EndOfMedia) {
-                       playing = false;
-                     }
-                   });
-  
-  QObject::connect(player, &QMediaPlayer::playbackStateChanged,
-                   [filepath = this->filepath](QMediaPlayer::PlaybackState state) {
-                     qDebug() << "Playback state for" << QString::fromStdString(filepath) << ":" << static_cast<int>(state);
+                   [filepath = this->filepath](QMediaPlayer::Error error,
+                                               const QString &desc) {
+                     qWarning() << "QMediaPlayer error for"
+                                << QString::fromStdString(filepath)
+                                << "- Error code:" << static_cast<int>(error)
+                                << "Message:" << desc;
                    });
                    });
-  
+
+  QObject::connect(
+      player, &QMediaPlayer::mediaStatusChanged,
+      [filepath = this->filepath, this](QMediaPlayer::MediaStatus status) {
+        qDebug() << "Media status for" << QString::fromStdString(filepath)
+                 << ":" << static_cast<int>(status);
+        if (status == QMediaPlayer::EndOfMedia) {
+          playing = false;
+        }
+      });
+
+  QObject::connect(
+      player, &QMediaPlayer::playbackStateChanged,
+      [filepath = this->filepath](QMediaPlayer::PlaybackState state) {
+        qDebug() << "Playback state for" << QString::fromStdString(filepath)
+                 << ":" << static_cast<int>(state);
+      });
+
   player->setSource(QUrl::fromLocalFile(QString::fromStdString(filePath)));
   player->setSource(QUrl::fromLocalFile(QString::fromStdString(filePath)));
   loaded = (player->error() == QMediaPlayer::NoError);
   loaded = (player->error() == QMediaPlayer::NoError);
 #else
 #else
@@ -60,13 +66,11 @@ void Music::cleanupPlayer() {
 
 
   markedForDeletion = true;
   markedForDeletion = true;
   QMediaPlayer *rawPlayer = player.data();
   QMediaPlayer *rawPlayer = player.data();
-  
+
   if (!rawPlayer) {
   if (!rawPlayer) {
     return;
     return;
   }
   }
 
 
-  // Don't call stop() - it can cause GStreamer double-free issues
-  // The destructor will handle cleanup properly
   if (QCoreApplication::instance() && mainThread) {
   if (QCoreApplication::instance() && mainThread) {
     rawPlayer->deleteLater();
     rawPlayer->deleteLater();
   }
   }
@@ -86,7 +90,6 @@ void Music::play(float volume, bool loop) {
     return;
     return;
   }
   }
 
 
-  // Check if already playing - if so, just update volume
   QMetaObject::invokeMethod(
   QMetaObject::invokeMethod(
       QCoreApplication::instance(),
       QCoreApplication::instance(),
       [p, output, volume, loop, this]() {
       [p, output, volume, loop, this]() {
@@ -94,21 +97,23 @@ void Music::play(float volume, bool loop) {
           return;
           return;
         }
         }
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
-        // Check current state
-        bool isCurrentlyPlaying = (p->playbackState() == QMediaPlayer::PlayingState);
-        
+
+        bool isCurrentlyPlaying =
+            (p->playbackState() == QMediaPlayer::PlayingState);
+
         if (output) {
         if (output) {
           output->setVolume(volume);
           output->setVolume(volume);
         }
         }
         p->setLoops(loop ? QMediaPlayer::Infinite : 1);
         p->setLoops(loop ? QMediaPlayer::Infinite : 1);
-        
-        // Only call play() if not already playing
+
         if (!isCurrentlyPlaying) {
         if (!isCurrentlyPlaying) {
-          qDebug() << "Starting playback for" << QString::fromStdString(filepath);
+          qDebug() << "Starting playback for"
+                   << QString::fromStdString(filepath);
           playing = true;
           playing = true;
           p->play();
           p->play();
         } else {
         } else {
-          qDebug() << "Already playing" << QString::fromStdString(filepath) << "- updating volume only";
+          qDebug() << "Already playing" << QString::fromStdString(filepath)
+                   << "- updating volume only";
         }
         }
 #else
 #else
         p->setVolume(static_cast<int>(volume * 100));
         p->setVolume(static_cast<int>(volume * 100));
@@ -226,7 +231,6 @@ void Music::fadeOut() {
     return;
     return;
   }
   }
 
 
-  // Fade to 0 volume then pause - safer than immediate stop
   QMetaObject::invokeMethod(
   QMetaObject::invokeMethod(
       QCoreApplication::instance(),
       QCoreApplication::instance(),
       [p, this]() {
       [p, this]() {
@@ -237,10 +241,11 @@ void Music::fadeOut() {
         if (p->audioOutput()) {
         if (p->audioOutput()) {
           p->audioOutput()->setVolume(0.0f);
           p->audioOutput()->setVolume(0.0f);
         }
         }
-        // Small delay before pausing to let volume change take effect
+
         QTimer::singleShot(50, [p, this]() {
         QTimer::singleShot(50, [p, this]() {
           if (p && p->playbackState() == QMediaPlayer::PlayingState) {
           if (p && p->playbackState() == QMediaPlayer::PlayingState) {
-            qDebug() << "Fading out and pausing" << QString::fromStdString(filepath);
+            qDebug() << "Fading out and pausing"
+                     << QString::fromStdString(filepath);
             p->pause();
             p->pause();
             playing = false;
             playing = false;
           }
           }

+ 1 - 1
game/audio/Music.h

@@ -20,7 +20,7 @@ public:
   void pause();
   void pause();
   void resume();
   void resume();
   void setVolume(float volume);
   void setVolume(float volume);
-  void fadeOut(); // Safer than immediate stop/pause
+  void fadeOut();
 
 
 private:
 private:
   void cleanupPlayer();
   void cleanupPlayer();

+ 125 - 62
game/audio/MusicPlayer.cpp

@@ -1,21 +1,21 @@
 #include "MusicPlayer.h"
 #include "MusicPlayer.h"
+#include "MiniaudioBackend.h"
 #include <QCoreApplication>
 #include <QCoreApplication>
 #include <QFileInfo>
 #include <QFileInfo>
 #include <QMetaObject>
 #include <QMetaObject>
 #include <QTimer>
 #include <QTimer>
 #include <QtGlobal>
 #include <QtGlobal>
-#include "MiniaudioBackend.h"
 
 
 using namespace Game::Audio;
 using namespace Game::Audio;
 
 
-static inline void requireGuiThread(const char* where) {
+static inline void requireGuiThread(const char *where) {
   if (!QCoreApplication::instance() ||
   if (!QCoreApplication::instance() ||
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
     qFatal("%s must be called on the GUI thread", where);
     qFatal("%s must be called on the GUI thread", where);
   }
   }
 }
 }
 
 
-MusicPlayer& MusicPlayer::getInstance() {
+MusicPlayer &MusicPlayer::getInstance() {
   static MusicPlayer instance;
   static MusicPlayer instance;
   return instance;
   return instance;
 }
 }
@@ -24,7 +24,8 @@ MusicPlayer::MusicPlayer() : QObject(nullptr) {}
 MusicPlayer::~MusicPlayer() { shutdown(); }
 MusicPlayer::~MusicPlayer() { shutdown(); }
 
 
 bool MusicPlayer::initialize(int musicChannels) {
 bool MusicPlayer::initialize(int musicChannels) {
-  if (m_initialized) return true;
+  if (m_initialized)
+    return true;
   if (!QCoreApplication::instance()) {
   if (!QCoreApplication::instance()) {
     qWarning() << "MusicPlayer: no Q(Gui)Application instance";
     qWarning() << "MusicPlayer: no Q(Gui)Application instance";
     return false;
     return false;
@@ -33,144 +34,206 @@ bool MusicPlayer::initialize(int musicChannels) {
 
 
   m_channelCount = std::max(1, musicChannels);
   m_channelCount = std::max(1, musicChannels);
   m_backend = new MiniaudioBackend(this);
   m_backend = new MiniaudioBackend(this);
-  if (!m_backend->initialize(/*deviceRate*/48000, /*outCh*/2, m_channelCount)) {
+  if (!m_backend->initialize(48000, 2, m_channelCount)) {
     qWarning() << "MusicPlayer: backend init failed";
     qWarning() << "MusicPlayer: backend init failed";
-    m_backend->deleteLater(); m_backend = nullptr; return false;
+    m_backend->deleteLater();
+    m_backend = nullptr;
+    return false;
   }
   }
 
 
   m_initialized = true;
   m_initialized = true;
-  qInfo() << "MusicPlayer initialized (miniaudio backend) channels:" << m_channelCount;
+  qInfo() << "MusicPlayer initialized (miniaudio backend) channels:"
+          << m_channelCount;
   return true;
   return true;
 }
 }
 
 
 void MusicPlayer::shutdown() {
 void MusicPlayer::shutdown() {
-  if (!m_initialized) return;
-  
-  // Marshal to GUI thread if needed
+  if (!m_initialized)
+    return;
+
   if (QCoreApplication::instance() &&
   if (QCoreApplication::instance() &&
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this](){ shutdown(); }, Qt::BlockingQueuedConnection);
+    QMetaObject::invokeMethod(
+        this, [this]() { shutdown(); }, Qt::BlockingQueuedConnection);
     return;
     return;
   }
   }
-  
+
   ensureOnGuiThread("MusicPlayer::shutdown");
   ensureOnGuiThread("MusicPlayer::shutdown");
-  if (m_backend) { m_backend->shutdown(); m_backend->deleteLater(); m_backend = nullptr; }
+  if (m_backend) {
+    m_backend->shutdown();
+    m_backend->deleteLater();
+    m_backend = nullptr;
+  }
   m_tracks.clear();
   m_tracks.clear();
   m_channelCount = 0;
   m_channelCount = 0;
   m_initialized = false;
   m_initialized = false;
 }
 }
 
 
-void MusicPlayer::registerTrack(const std::string& trackId, const std::string& filePath) {
-  // marshal to GUI
+void MusicPlayer::registerTrack(const std::string &trackId,
+                                const std::string &filePath) {
+
   if (QCoreApplication::instance() &&
   if (QCoreApplication::instance() &&
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, trackId, filePath](){ registerTrack(trackId, filePath); }, Qt::QueuedConnection);
+    QMetaObject::invokeMethod(
+        this, [this, trackId, filePath]() { registerTrack(trackId, filePath); },
+        Qt::QueuedConnection);
     return;
     return;
   }
   }
   ensureOnGuiThread("MusicPlayer::registerTrack");
   ensureOnGuiThread("MusicPlayer::registerTrack");
 
 
   QFileInfo fi(QString::fromStdString(filePath));
   QFileInfo fi(QString::fromStdString(filePath));
   if (!fi.exists()) {
   if (!fi.exists()) {
-    qWarning() << "MusicPlayer: Missing asset" << QString::fromStdString(trackId)
-               << "->" << fi.absoluteFilePath();
+    qWarning() << "MusicPlayer: Missing asset"
+               << QString::fromStdString(trackId) << "->"
+               << fi.absoluteFilePath();
     return;
     return;
   }
   }
   m_tracks[trackId] = fi.absoluteFilePath();
   m_tracks[trackId] = fi.absoluteFilePath();
 
 
   if (m_backend) {
   if (m_backend) {
-    if (!m_backend->predecode(QString::fromStdString(trackId), fi.absoluteFilePath())) {
-      qWarning() << "MusicPlayer: predecode failed for" << fi.absoluteFilePath();
+    if (!m_backend->predecode(QString::fromStdString(trackId),
+                              fi.absoluteFilePath())) {
+      qWarning() << "MusicPlayer: predecode failed for"
+                 << fi.absoluteFilePath();
     } else {
     } else {
       qDebug() << "MusicPlayer: predecoded" << fi.absoluteFilePath();
       qDebug() << "MusicPlayer: predecoded" << fi.absoluteFilePath();
     }
     }
   }
   }
 }
 }
 
 
-// Back-compat on channel 0
-void MusicPlayer::play(const std::string& id, float v, bool loop){ play(id, v, loop, m_defaultChannel, 250); }
-void MusicPlayer::stop()                                    { stop(m_defaultChannel, 150); }
-void MusicPlayer::pause()                                   { pause(m_defaultChannel); }
-void MusicPlayer::resume()                                  { resume(m_defaultChannel); }
-void MusicPlayer::setVolume(float v)                        { setVolume(m_defaultChannel, v, 0); }
-
-// Channel-aware
-int MusicPlayer::play(const std::string& id, float vol, bool loop, int channel, int fadeMs) {
-  if (!m_initialized || !m_backend) { qWarning() << "MusicPlayer not initialized"; return -1; }
+void MusicPlayer::play(const std::string &id, float v, bool loop) {
+  play(id, v, loop, m_defaultChannel, 250);
+}
+void MusicPlayer::stop() { stop(m_defaultChannel, 150); }
+void MusicPlayer::pause() { pause(m_defaultChannel); }
+void MusicPlayer::resume() { resume(m_defaultChannel); }
+void MusicPlayer::setVolume(float v) { setVolume(m_defaultChannel, v, 0); }
+
+int MusicPlayer::play(const std::string &id, float vol, bool loop, int channel,
+                      int fadeMs) {
+  if (!m_initialized || !m_backend) {
+    qWarning() << "MusicPlayer not initialized";
+    return -1;
+  }
   int result = -1;
   int result = -1;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, id, vol, loop, channel, fadeMs, &result]() mutable {
-      int ch = channel < 0 ? findFreeChannel() : std::min(channel, m_channelCount - 1);
-      play_gui(id, vol, loop, ch, fadeMs); result = ch;
-    }, Qt::BlockingQueuedConnection);
+    QMetaObject::invokeMethod(
+        this,
+        [this, id, vol, loop, channel, fadeMs, &result]() mutable {
+          int ch = channel < 0 ? findFreeChannel()
+                               : std::min(channel, m_channelCount - 1);
+          play_gui(id, vol, loop, ch, fadeMs);
+          result = ch;
+        },
+        Qt::BlockingQueuedConnection);
     return result;
     return result;
   }
   }
-  int ch = channel < 0 ? findFreeChannel() : std::min(channel, m_channelCount - 1);
+  int ch =
+      channel < 0 ? findFreeChannel() : std::min(channel, m_channelCount - 1);
   play_gui(id, vol, loop, ch, fadeMs);
   play_gui(id, vol, loop, ch, fadeMs);
   return ch;
   return ch;
 }
 }
 
 
 void MusicPlayer::stop(int ch, int ms) {
 void MusicPlayer::stop(int ch, int ms) {
-  if (!m_initialized || !m_backend) return;
+  if (!m_initialized || !m_backend)
+    return;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, ch, ms](){ stop_gui(ch, ms); }, Qt::QueuedConnection); return;
+    QMetaObject::invokeMethod(
+        this, [this, ch, ms]() { stop_gui(ch, ms); }, Qt::QueuedConnection);
+    return;
   }
   }
   stop_gui(ch, ms);
   stop_gui(ch, ms);
 }
 }
 void MusicPlayer::pause(int ch) {
 void MusicPlayer::pause(int ch) {
-  if (!m_initialized || !m_backend) return;
+  if (!m_initialized || !m_backend)
+    return;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, ch](){ pause_gui(ch); }, Qt::QueuedConnection); return;
+    QMetaObject::invokeMethod(
+        this, [this, ch]() { pause_gui(ch); }, Qt::QueuedConnection);
+    return;
   }
   }
   pause_gui(ch);
   pause_gui(ch);
 }
 }
 void MusicPlayer::resume(int ch) {
 void MusicPlayer::resume(int ch) {
-  if (!m_initialized || !m_backend) return;
+  if (!m_initialized || !m_backend)
+    return;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, ch](){ resume_gui(ch); }, Qt::QueuedConnection); return;
+    QMetaObject::invokeMethod(
+        this, [this, ch]() { resume_gui(ch); }, Qt::QueuedConnection);
+    return;
   }
   }
   resume_gui(ch);
   resume_gui(ch);
 }
 }
 void MusicPlayer::setVolume(int ch, float v, int ms) {
 void MusicPlayer::setVolume(int ch, float v, int ms) {
-  if (!m_initialized || !m_backend) return;
+  if (!m_initialized || !m_backend)
+    return;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, ch, v, ms](){ setVolume_gui(ch, v, ms); }, Qt::QueuedConnection); return;
+    QMetaObject::invokeMethod(
+        this, [this, ch, v, ms]() { setVolume_gui(ch, v, ms); },
+        Qt::QueuedConnection);
+    return;
   }
   }
   setVolume_gui(ch, v, ms);
   setVolume_gui(ch, v, ms);
 }
 }
 void MusicPlayer::stopAll(int ms) {
 void MusicPlayer::stopAll(int ms) {
-  if (!m_initialized || !m_backend) return;
+  if (!m_initialized || !m_backend)
+    return;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, ms](){ stopAll_gui(ms); }, Qt::QueuedConnection); return;
+    QMetaObject::invokeMethod(
+        this, [this, ms]() { stopAll_gui(ms); }, Qt::QueuedConnection);
+    return;
   }
   }
   stopAll_gui(ms);
   stopAll_gui(ms);
 }
 }
 void MusicPlayer::setMasterVolume(float v, int ms) {
 void MusicPlayer::setMasterVolume(float v, int ms) {
-  if (!m_initialized || !m_backend) return;
+  if (!m_initialized || !m_backend)
+    return;
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
-    QMetaObject::invokeMethod(this, [this, v, ms](){ setMasterVolume_gui(v, ms); }, Qt::QueuedConnection); return;
+    QMetaObject::invokeMethod(
+        this, [this, v, ms]() { setMasterVolume_gui(v, ms); },
+        Qt::QueuedConnection);
+    return;
   }
   }
   setMasterVolume_gui(v, ms);
   setMasterVolume_gui(v, ms);
 }
 }
 
 
-bool MusicPlayer::isPlaying() const { return m_backend && m_backend->anyChannelPlaying(); }
-bool MusicPlayer::isPlaying(int ch) const { return m_backend && m_backend->channelPlaying(ch); }
+bool MusicPlayer::isPlaying() const {
+  return m_backend && m_backend->anyChannelPlaying();
+}
+bool MusicPlayer::isPlaying(int ch) const {
+  return m_backend && m_backend->channelPlaying(ch);
+}
 
 
-void MusicPlayer::ensureOnGuiThread(const char* where) const { requireGuiThread(where); }
-int  MusicPlayer::findFreeChannel() const {
-  if (!m_backend) return 0;
-  for (int i = 0; i < m_channelCount; ++i) if (!m_backend->channelPlaying(i)) return i;
+void MusicPlayer::ensureOnGuiThread(const char *where) const {
+  requireGuiThread(where);
+}
+int MusicPlayer::findFreeChannel() const {
+  if (!m_backend)
+    return 0;
+  for (int i = 0; i < m_channelCount; ++i)
+    if (!m_backend->channelPlaying(i))
+      return i;
   return 0;
   return 0;
 }
 }
 
 
-void MusicPlayer::play_gui(const std::string& id, float vol, bool loop, int ch, int fadeMs) {
-  if (!m_backend) return;
+void MusicPlayer::play_gui(const std::string &id, float vol, bool loop, int ch,
+                           int fadeMs) {
+  if (!m_backend)
+    return;
   auto it = m_tracks.find(id);
   auto it = m_tracks.find(id);
-  if (it == m_tracks.end()) { qWarning() << "Unknown trackId:" << QString::fromStdString(id); return; }
+  if (it == m_tracks.end()) {
+    qWarning() << "Unknown trackId:" << QString::fromStdString(id);
+    return;
+  }
   m_backend->play(ch, QString::fromStdString(id), vol, loop, fadeMs);
   m_backend->play(ch, QString::fromStdString(id), vol, loop, fadeMs);
 }
 }
-void MusicPlayer::stop_gui(int ch, int ms)           { m_backend->stop(ch, ms); }
-void MusicPlayer::pause_gui(int ch)                  { m_backend->pause(ch); }
-void MusicPlayer::resume_gui(int ch)                 { m_backend->resume(ch); }
-void MusicPlayer::setVolume_gui(int ch, float v, int ms) { m_backend->setVolume(ch, v, ms); }
-void MusicPlayer::setMasterVolume_gui(float v, int ms)   { m_backend->setMasterVolume(v, ms); }
-void MusicPlayer::stopAll_gui(int ms)                { m_backend->stopAll(ms); }
+void MusicPlayer::stop_gui(int ch, int ms) { m_backend->stop(ch, ms); }
+void MusicPlayer::pause_gui(int ch) { m_backend->pause(ch); }
+void MusicPlayer::resume_gui(int ch) { m_backend->resume(ch); }
+void MusicPlayer::setVolume_gui(int ch, float v, int ms) {
+  m_backend->setVolume(ch, v, ms);
+}
+void MusicPlayer::setMasterVolume_gui(float v, int ms) {
+  m_backend->setMasterVolume(v, ms);
+}
+void MusicPlayer::stopAll_gui(int ms) { m_backend->stopAll(ms); }

+ 19 - 25
game/audio/MusicPlayer.h

@@ -1,12 +1,12 @@
 #pragma once
 #pragma once
+#include "MiniaudioBackend.h"
 #include <QObject>
 #include <QObject>
 #include <QPointer>
 #include <QPointer>
-#include <QVector>
 #include <QString>
 #include <QString>
 #include <QThread>
 #include <QThread>
-#include <unordered_map>
+#include <QVector>
 #include <string>
 #include <string>
-#include "MiniaudioBackend.h"  // Include instead of forward-declare
+#include <unordered_map>
 
 
 namespace Game {
 namespace Game {
 namespace Audio {
 namespace Audio {
@@ -14,62 +14,56 @@ namespace Audio {
 class MusicPlayer final : public QObject {
 class MusicPlayer final : public QObject {
   Q_OBJECT
   Q_OBJECT
 public:
 public:
-  static MusicPlayer& getInstance();
+  static MusicPlayer &getInstance();
 
 
-  // Call from GUI thread after Q(Gui)Application exists
   bool initialize(int musicChannels = 4);
   bool initialize(int musicChannels = 4);
   void shutdown();
   void shutdown();
 
 
-  // Track registry (id -> file path)
-  void registerTrack(const std::string& trackId, const std::string& filePath);
+  void registerTrack(const std::string &trackId, const std::string &filePath);
 
 
-  // Back-compat (channel 0)
-  void play(const std::string& trackId, float volume = 1.0f, bool loop = true);
+  void play(const std::string &trackId, float volume = 1.0f, bool loop = true);
   void stop();
   void stop();
   void pause();
   void pause();
   void resume();
   void resume();
   void setVolume(float volume);
   void setVolume(float volume);
 
 
-  // Channel-aware (parallel layers)
-  int  play(const std::string& trackId, float volume, bool loop, int channel, int fadeMs);
+  int play(const std::string &trackId, float volume, bool loop, int channel,
+           int fadeMs);
   void stop(int channel, int fadeMs = 150);
   void stop(int channel, int fadeMs = 150);
   void pause(int channel);
   void pause(int channel);
   void resume(int channel);
   void resume(int channel);
   void setVolume(int channel, float volume, int fadeMs = 0);
   void setVolume(int channel, float volume, int fadeMs = 0);
 
 
-  // Global
   void stopAll(int fadeMs = 150);
   void stopAll(int fadeMs = 150);
   void setMasterVolume(float volume, int fadeMs = 0);
   void setMasterVolume(float volume, int fadeMs = 0);
 
 
-  // Queries
   bool isPlaying() const;
   bool isPlaying() const;
   bool isPlaying(int channel) const;
   bool isPlaying(int channel) const;
-  
-  // Access to backend for sound effects
-  MiniaudioBackend* getBackend() { return m_backend.data(); }
+
+  MiniaudioBackend *getBackend() { return m_backend.data(); }
 
 
 private:
 private:
   explicit MusicPlayer();
   explicit MusicPlayer();
   ~MusicPlayer() override;
   ~MusicPlayer() override;
 
 
-  void ensureOnGuiThread(const char* where) const;
+  void ensureOnGuiThread(const char *where) const;
 
 
-  // GUI-thread impls
-  void play_gui(const std::string& trackId, float volume, bool loop, int channel, int fadeMs);
+  void play_gui(const std::string &trackId, float volume, bool loop,
+                int channel, int fadeMs);
   void stop_gui(int channel, int fadeMs);
   void stop_gui(int channel, int fadeMs);
   void pause_gui(int channel);
   void pause_gui(int channel);
   void resume_gui(int channel);
   void resume_gui(int channel);
   void setVolume_gui(int channel, float volume, int fadeMs);
   void setVolume_gui(int channel, float volume, int fadeMs);
   void setMasterVolume_gui(float volume, int fadeMs);
   void setMasterVolume_gui(float volume, int fadeMs);
   void stopAll_gui(int fadeMs);
   void stopAll_gui(int fadeMs);
-  int  findFreeChannel() const;
+  int findFreeChannel() const;
 
 
 private:
 private:
-  QPointer<MiniaudioBackend> m_backend; // heavy lifter
-  std::unordered_map<std::string, QString> m_tracks; // id -> absolute path
-  int   m_channelCount {0};
-  int   m_defaultChannel {0};
-  bool  m_initialized {false};
+  QPointer<MiniaudioBackend> m_backend;
+  std::unordered_map<std::string, QString> m_tracks;
+  int m_channelCount{0};
+  int m_defaultChannel{0};
+  bool m_initialized{false};
 };
 };
 
 
 } // namespace Audio
 } // namespace Audio

+ 18 - 36
game/audio/Sound.cpp

@@ -1,30 +1,23 @@
 #include "Sound.h"
 #include "Sound.h"
 #include "MiniaudioBackend.h"
 #include "MiniaudioBackend.h"
+#include <QCryptographicHash>
 #include <QDebug>
 #include <QDebug>
 #include <QFileInfo>
 #include <QFileInfo>
-#include <QCryptographicHash>
 
 
-Sound::Sound(const std::string &filePath, MiniaudioBackend* backend)
-    : QObject(nullptr)
-    , m_filepath(filePath)
-    , m_backend(backend)
-    , m_loaded(false)
-    , m_volume(1.0f) {
-  
-  // Generate a unique track ID from the file path
+Sound::Sound(const std::string &filePath, MiniaudioBackend *backend)
+    : QObject(nullptr), m_filepath(filePath), m_backend(backend),
+      m_loaded(false), m_volume(1.0f) {
+
   QByteArray hash = QCryptographicHash::hash(
   QByteArray hash = QCryptographicHash::hash(
-    QByteArray::fromStdString(filePath), 
-    QCryptographicHash::Md5
-  );
+      QByteArray::fromStdString(filePath), QCryptographicHash::Md5);
   m_trackId = "sound_" + QString(hash.toHex());
   m_trackId = "sound_" + QString(hash.toHex());
-  
+
   QFileInfo fi(QString::fromStdString(m_filepath));
   QFileInfo fi(QString::fromStdString(m_filepath));
   if (!fi.exists()) {
   if (!fi.exists()) {
     qWarning() << "Sound: File does not exist:" << fi.absoluteFilePath();
     qWarning() << "Sound: File does not exist:" << fi.absoluteFilePath();
     return;
     return;
   }
   }
 
 
-  // If backend is available, predecode the sound
   if (m_backend) {
   if (m_backend) {
     m_loaded = m_backend->predecode(m_trackId, fi.absoluteFilePath());
     m_loaded = m_backend->predecode(m_trackId, fi.absoluteFilePath());
     if (m_loaded) {
     if (m_loaded) {
@@ -33,16 +26,14 @@ Sound::Sound(const std::string &filePath, MiniaudioBackend* backend)
   }
   }
 }
 }
 
 
-Sound::~Sound() {
-  // Sound data stays in backend cache
-}
+Sound::~Sound() {}
+
+void Sound::setBackend(MiniaudioBackend *backend) {
+  if (m_backend == backend)
+    return;
 
 
-void Sound::setBackend(MiniaudioBackend* backend) {
-  if (m_backend == backend) return;
-  
   m_backend = backend;
   m_backend = backend;
-  
-  // Reload if we have a new backend
+
   if (m_backend && !m_loaded) {
   if (m_backend && !m_loaded) {
     QFileInfo fi(QString::fromStdString(m_filepath));
     QFileInfo fi(QString::fromStdString(m_filepath));
     if (fi.exists()) {
     if (fi.exists()) {
@@ -51,9 +42,7 @@ void Sound::setBackend(MiniaudioBackend* backend) {
   }
   }
 }
 }
 
 
-bool Sound::isLoaded() const {
-  return m_loaded.load();
-}
+bool Sound::isLoaded() const { return m_loaded.load(); }
 
 
 void Sound::play(float volume, bool loop) {
 void Sound::play(float volume, bool loop) {
   if (!m_backend || !m_loaded) {
   if (!m_backend || !m_loaded) {
@@ -63,18 +52,11 @@ void Sound::play(float volume, bool loop) {
 
 
   m_volume = volume;
   m_volume = volume;
   m_backend->playSound(m_trackId, volume, loop);
   m_backend->playSound(m_trackId, volume, loop);
-  
-  qDebug() << "Sound: Playing" << QString::fromStdString(m_filepath) 
+
+  qDebug() << "Sound: Playing" << QString::fromStdString(m_filepath)
            << "volume:" << volume << "loop:" << loop;
            << "volume:" << volume << "loop:" << loop;
 }
 }
 
 
-void Sound::stop() {
-  // Note: Individual sound effect stopping not implemented yet
-  // Sound effects play to completion or can be stopped by clearing all
-}
+void Sound::stop() {}
 
 
-void Sound::setVolume(float volume) {
-  m_volume = volume;
-  // Note: Volume change for already-playing sounds not implemented
-  // This will affect next playback
-}
+void Sound::setVolume(float volume) { m_volume = volume; }

+ 5 - 4
game/audio/Sound.h

@@ -10,20 +10,21 @@ class MiniaudioBackend;
 class Sound : public QObject {
 class Sound : public QObject {
   Q_OBJECT
   Q_OBJECT
 public:
 public:
-  explicit Sound(const std::string &filePath, MiniaudioBackend* backend = nullptr);
+  explicit Sound(const std::string &filePath,
+                 MiniaudioBackend *backend = nullptr);
   ~Sound();
   ~Sound();
 
 
   bool isLoaded() const;
   bool isLoaded() const;
   void play(float volume = 1.0f, bool loop = false);
   void play(float volume = 1.0f, bool loop = false);
   void stop();
   void stop();
   void setVolume(float volume);
   void setVolume(float volume);
-  
-  void setBackend(MiniaudioBackend* backend);
+
+  void setBackend(MiniaudioBackend *backend);
 
 
 private:
 private:
   std::string m_filepath;
   std::string m_filepath;
   QString m_trackId;
   QString m_trackId;
-  MiniaudioBackend* m_backend;
+  MiniaudioBackend *m_backend;
   std::atomic<bool> m_loaded;
   std::atomic<bool> m_loaded;
   std::atomic<float> m_volume;
   std::atomic<float> m_volume;
 };
 };

+ 3 - 2
game/core/component.h

@@ -164,8 +164,9 @@ class ProductionComponent : public Component {
 public:
 public:
   ProductionComponent()
   ProductionComponent()
       : inProgress(false), buildTime(4.0f), timeRemaining(0.0f),
       : inProgress(false), buildTime(4.0f), timeRemaining(0.0f),
-        producedCount(0), maxUnits(5), productType(Game::Units::TroopType::Archer), rallyX(0.0f),
-        rallyZ(0.0f), rallySet(false), villagerCost(1) {}
+        producedCount(0), maxUnits(5),
+        productType(Game::Units::TroopType::Archer), rallyX(0.0f), rallyZ(0.0f),
+        rallySet(false), villagerCost(1) {}
 
 
   bool inProgress;
   bool inProgress;
   float buildTime;
   float buildTime;

+ 49 - 49
game/core/serialization.cpp

@@ -1,10 +1,10 @@
 #include "serialization.h"
 #include "serialization.h"
+#include "../map/terrain.h"
+#include "../map/terrain_service.h"
 #include "../units/troop_type.h"
 #include "../units/troop_type.h"
 #include "component.h"
 #include "component.h"
 #include "entity.h"
 #include "entity.h"
 #include "world.h"
 #include "world.h"
-#include "../map/terrain.h"
-#include "../map/terrain_service.h"
 #include <QDebug>
 #include <QDebug>
 #include <QFile>
 #include <QFile>
 #include <QJsonArray>
 #include <QJsonArray>
@@ -185,8 +185,8 @@ QJsonObject Serialization::serializeEntity(const Entity *entity) {
     productionObj["timeRemaining"] = production->timeRemaining;
     productionObj["timeRemaining"] = production->timeRemaining;
     productionObj["producedCount"] = production->producedCount;
     productionObj["producedCount"] = production->producedCount;
     productionObj["maxUnits"] = production->maxUnits;
     productionObj["maxUnits"] = production->maxUnits;
-    productionObj["productType"] =
-        QString::fromStdString(Game::Units::troopTypeToString(production->productType));
+    productionObj["productType"] = QString::fromStdString(
+        Game::Units::troopTypeToString(production->productType));
     productionObj["rallyX"] = production->rallyX;
     productionObj["rallyX"] = production->rallyX;
     productionObj["rallyZ"] = production->rallyZ;
     productionObj["rallyZ"] = production->rallyZ;
     productionObj["rallySet"] = production->rallySet;
     productionObj["rallySet"] = production->rallySet;
@@ -194,7 +194,8 @@ QJsonObject Serialization::serializeEntity(const Entity *entity) {
 
 
     QJsonArray queueArray;
     QJsonArray queueArray;
     for (const auto &queued : production->productionQueue) {
     for (const auto &queued : production->productionQueue) {
-      queueArray.append(QString::fromStdString(Game::Units::troopTypeToString(queued)));
+      queueArray.append(
+          QString::fromStdString(Game::Units::troopTypeToString(queued)));
     }
     }
     productionObj["queue"] = queueArray;
     productionObj["queue"] = queueArray;
     entityObj["production"] = productionObj;
     entityObj["production"] = productionObj;
@@ -361,8 +362,8 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
         static_cast<float>(productionObj["timeRemaining"].toDouble());
         static_cast<float>(productionObj["timeRemaining"].toDouble());
     production->producedCount = productionObj["producedCount"].toInt(0);
     production->producedCount = productionObj["producedCount"].toInt(0);
     production->maxUnits = productionObj["maxUnits"].toInt(0);
     production->maxUnits = productionObj["maxUnits"].toInt(0);
-    production->productType =
-        Game::Units::troopTypeFromString(productionObj["productType"].toString().toStdString());
+    production->productType = Game::Units::troopTypeFromString(
+        productionObj["productType"].toString().toStdString());
     production->rallyX = static_cast<float>(productionObj["rallyX"].toDouble());
     production->rallyX = static_cast<float>(productionObj["rallyX"].toDouble());
     production->rallyZ = static_cast<float>(productionObj["rallyZ"].toDouble());
     production->rallyZ = static_cast<float>(productionObj["rallyZ"].toDouble());
     production->rallySet = productionObj["rallySet"].toBool(false);
     production->rallySet = productionObj["rallySet"].toBool(false);
@@ -372,7 +373,8 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     const auto queueArray = productionObj["queue"].toArray();
     const auto queueArray = productionObj["queue"].toArray();
     production->productionQueue.reserve(queueArray.size());
     production->productionQueue.reserve(queueArray.size());
     for (const auto &value : queueArray) {
     for (const auto &value : queueArray) {
-      production->productionQueue.push_back(Game::Units::troopTypeFromString(value.toString().toStdString()));
+      production->productionQueue.push_back(
+          Game::Units::troopTypeFromString(value.toString().toStdString()));
     }
     }
   }
   }
 
 
@@ -392,9 +394,9 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
   }
   }
 }
 }
 
 
-QJsonObject Serialization::serializeTerrain(
-    const Game::Map::TerrainHeightMap *heightMap,
-    const Game::Map::BiomeSettings &biome) {
+QJsonObject
+Serialization::serializeTerrain(const Game::Map::TerrainHeightMap *heightMap,
+                                const Game::Map::BiomeSettings &biome) {
   QJsonObject terrainObj;
   QJsonObject terrainObj;
 
 
   if (!heightMap) {
   if (!heightMap) {
@@ -507,30 +509,30 @@ void Serialization::deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
 
 
   if (json.contains("biome")) {
   if (json.contains("biome")) {
     const auto biomeObj = json["biome"].toObject();
     const auto biomeObj = json["biome"].toObject();
-    biome.grassPrimary = QVector3D(
-        static_cast<float>(biomeObj["grassPrimaryR"].toDouble(0.3)),
-        static_cast<float>(biomeObj["grassPrimaryG"].toDouble(0.6)),
-        static_cast<float>(biomeObj["grassPrimaryB"].toDouble(0.28)));
+    biome.grassPrimary =
+        QVector3D(static_cast<float>(biomeObj["grassPrimaryR"].toDouble(0.3)),
+                  static_cast<float>(biomeObj["grassPrimaryG"].toDouble(0.6)),
+                  static_cast<float>(biomeObj["grassPrimaryB"].toDouble(0.28)));
     biome.grassSecondary = QVector3D(
     biome.grassSecondary = QVector3D(
         static_cast<float>(biomeObj["grassSecondaryR"].toDouble(0.44)),
         static_cast<float>(biomeObj["grassSecondaryR"].toDouble(0.44)),
         static_cast<float>(biomeObj["grassSecondaryG"].toDouble(0.7)),
         static_cast<float>(biomeObj["grassSecondaryG"].toDouble(0.7)),
         static_cast<float>(biomeObj["grassSecondaryB"].toDouble(0.32)));
         static_cast<float>(biomeObj["grassSecondaryB"].toDouble(0.32)));
-    biome.grassDry = QVector3D(
-        static_cast<float>(biomeObj["grassDryR"].toDouble(0.72)),
-        static_cast<float>(biomeObj["grassDryG"].toDouble(0.66)),
-        static_cast<float>(biomeObj["grassDryB"].toDouble(0.48)));
-    biome.soilColor = QVector3D(
-        static_cast<float>(biomeObj["soilColorR"].toDouble(0.28)),
-        static_cast<float>(biomeObj["soilColorG"].toDouble(0.24)),
-        static_cast<float>(biomeObj["soilColorB"].toDouble(0.18)));
-    biome.rockLow = QVector3D(
-        static_cast<float>(biomeObj["rockLowR"].toDouble(0.48)),
-        static_cast<float>(biomeObj["rockLowG"].toDouble(0.46)),
-        static_cast<float>(biomeObj["rockLowB"].toDouble(0.44)));
-    biome.rockHigh = QVector3D(
-        static_cast<float>(biomeObj["rockHighR"].toDouble(0.68)),
-        static_cast<float>(biomeObj["rockHighG"].toDouble(0.69)),
-        static_cast<float>(biomeObj["rockHighB"].toDouble(0.73)));
+    biome.grassDry =
+        QVector3D(static_cast<float>(biomeObj["grassDryR"].toDouble(0.72)),
+                  static_cast<float>(biomeObj["grassDryG"].toDouble(0.66)),
+                  static_cast<float>(biomeObj["grassDryB"].toDouble(0.48)));
+    biome.soilColor =
+        QVector3D(static_cast<float>(biomeObj["soilColorR"].toDouble(0.28)),
+                  static_cast<float>(biomeObj["soilColorG"].toDouble(0.24)),
+                  static_cast<float>(biomeObj["soilColorB"].toDouble(0.18)));
+    biome.rockLow =
+        QVector3D(static_cast<float>(biomeObj["rockLowR"].toDouble(0.48)),
+                  static_cast<float>(biomeObj["rockLowG"].toDouble(0.46)),
+                  static_cast<float>(biomeObj["rockLowB"].toDouble(0.44)));
+    biome.rockHigh =
+        QVector3D(static_cast<float>(biomeObj["rockHighR"].toDouble(0.68)),
+                  static_cast<float>(biomeObj["rockHighG"].toDouble(0.69)),
+                  static_cast<float>(biomeObj["rockHighB"].toDouble(0.73)));
     biome.patchDensity =
     biome.patchDensity =
         static_cast<float>(biomeObj["patchDensity"].toDouble(4.5));
         static_cast<float>(biomeObj["patchDensity"].toDouble(4.5));
     biome.patchJitter =
     biome.patchJitter =
@@ -598,8 +600,7 @@ void Serialization::deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
     const auto typesArray = json["terrainTypes"].toArray();
     const auto typesArray = json["terrainTypes"].toArray();
     terrainTypes.reserve(typesArray.size());
     terrainTypes.reserve(typesArray.size());
     for (const auto &val : typesArray) {
     for (const auto &val : typesArray) {
-      terrainTypes.push_back(
-          static_cast<Game::Map::TerrainType>(val.toInt(0)));
+      terrainTypes.push_back(static_cast<Game::Map::TerrainType>(val.toInt(0)));
     }
     }
   }
   }
 
 
@@ -610,14 +611,13 @@ void Serialization::deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
     for (const auto &val : riversArray) {
     for (const auto &val : riversArray) {
       const auto riverObj = val.toObject();
       const auto riverObj = val.toObject();
       Game::Map::RiverSegment river;
       Game::Map::RiverSegment river;
-      river.start = QVector3D(
-          static_cast<float>(riverObj["startX"].toDouble(0.0)),
-          static_cast<float>(riverObj["startY"].toDouble(0.0)),
-          static_cast<float>(riverObj["startZ"].toDouble(0.0)));
-      river.end = QVector3D(
-          static_cast<float>(riverObj["endX"].toDouble(0.0)),
-          static_cast<float>(riverObj["endY"].toDouble(0.0)),
-          static_cast<float>(riverObj["endZ"].toDouble(0.0)));
+      river.start =
+          QVector3D(static_cast<float>(riverObj["startX"].toDouble(0.0)),
+                    static_cast<float>(riverObj["startY"].toDouble(0.0)),
+                    static_cast<float>(riverObj["startZ"].toDouble(0.0)));
+      river.end = QVector3D(static_cast<float>(riverObj["endX"].toDouble(0.0)),
+                            static_cast<float>(riverObj["endY"].toDouble(0.0)),
+                            static_cast<float>(riverObj["endZ"].toDouble(0.0)));
       river.width = static_cast<float>(riverObj["width"].toDouble(2.0));
       river.width = static_cast<float>(riverObj["width"].toDouble(2.0));
       rivers.push_back(river);
       rivers.push_back(river);
     }
     }
@@ -630,14 +630,14 @@ void Serialization::deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
     for (const auto &val : bridgesArray) {
     for (const auto &val : bridgesArray) {
       const auto bridgeObj = val.toObject();
       const auto bridgeObj = val.toObject();
       Game::Map::Bridge bridge;
       Game::Map::Bridge bridge;
-      bridge.start = QVector3D(
-          static_cast<float>(bridgeObj["startX"].toDouble(0.0)),
-          static_cast<float>(bridgeObj["startY"].toDouble(0.0)),
-          static_cast<float>(bridgeObj["startZ"].toDouble(0.0)));
-      bridge.end = QVector3D(
-          static_cast<float>(bridgeObj["endX"].toDouble(0.0)),
-          static_cast<float>(bridgeObj["endY"].toDouble(0.0)),
-          static_cast<float>(bridgeObj["endZ"].toDouble(0.0)));
+      bridge.start =
+          QVector3D(static_cast<float>(bridgeObj["startX"].toDouble(0.0)),
+                    static_cast<float>(bridgeObj["startY"].toDouble(0.0)),
+                    static_cast<float>(bridgeObj["startZ"].toDouble(0.0)));
+      bridge.end =
+          QVector3D(static_cast<float>(bridgeObj["endX"].toDouble(0.0)),
+                    static_cast<float>(bridgeObj["endY"].toDouble(0.0)),
+                    static_cast<float>(bridgeObj["endZ"].toDouble(0.0)));
       bridge.width = static_cast<float>(bridgeObj["width"].toDouble(3.0));
       bridge.width = static_cast<float>(bridgeObj["width"].toDouble(3.0));
       bridge.height = static_cast<float>(bridgeObj["height"].toDouble(0.5));
       bridge.height = static_cast<float>(bridgeObj["height"].toDouble(0.5));
       bridges.push_back(bridge);
       bridges.push_back(bridge);

+ 5 - 4
game/core/serialization.h

@@ -8,8 +8,8 @@ namespace Game {
 namespace Map {
 namespace Map {
 class TerrainHeightMap;
 class TerrainHeightMap;
 struct BiomeSettings;
 struct BiomeSettings;
-}
-}
+} // namespace Map
+} // namespace Game
 
 
 namespace Engine::Core {
 namespace Engine::Core {
 
 
@@ -21,8 +21,9 @@ public:
   static QJsonDocument serializeWorld(const class World *world);
   static QJsonDocument serializeWorld(const class World *world);
   static void deserializeWorld(class World *world, const QJsonDocument &doc);
   static void deserializeWorld(class World *world, const QJsonDocument &doc);
 
 
-  static QJsonObject serializeTerrain(const Game::Map::TerrainHeightMap *heightMap,
-                                      const Game::Map::BiomeSettings &biome);
+  static QJsonObject
+  serializeTerrain(const Game::Map::TerrainHeightMap *heightMap,
+                   const Game::Map::BiomeSettings &biome);
   static void deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
   static void deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
                                  Game::Map::BiomeSettings &biome,
                                  Game::Map::BiomeSettings &biome,
                                  const QJsonObject &json);
                                  const QJsonObject &json);

+ 2 - 1
game/map/level_loader.cpp

@@ -70,7 +70,8 @@ LevelLoadResult LevelLoader::loadFromAssets(const QString &mapPath,
         sp.playerId = 0;
         sp.playerId = 0;
         sp.unitType = "archer";
         sp.unitType = "archer";
         sp.aiControlled = !owners.isPlayer(sp.playerId);
         sp.aiControlled = !owners.isPlayer(sp.playerId);
-        if (auto unit = reg->create(Game::Units::TroopType::Archer, world, sp)) {
+        if (auto unit =
+                reg->create(Game::Units::TroopType::Archer, world, sp)) {
           res.playerUnitId = unit->id();
           res.playerUnitId = unit->id();
         } else {
         } else {
           qWarning() << "LevelLoader: Fallback archer spawn failed";
           qWarning() << "LevelLoader: Fallback archer spawn failed";

+ 6 - 6
game/map/terrain.cpp

@@ -604,28 +604,28 @@ void TerrainHeightMap::restoreFromData(
     const std::vector<TerrainType> &terrainTypes,
     const std::vector<TerrainType> &terrainTypes,
     const std::vector<RiverSegment> &rivers,
     const std::vector<RiverSegment> &rivers,
     const std::vector<Bridge> &bridges) {
     const std::vector<Bridge> &bridges) {
-  
+
   const size_t expectedSize = static_cast<size_t>(m_width * m_height);
   const size_t expectedSize = static_cast<size_t>(m_width * m_height);
-  
+
   if (heights.size() == expectedSize) {
   if (heights.size() == expectedSize) {
     m_heights = heights;
     m_heights = heights;
   }
   }
-  
+
   if (terrainTypes.size() == expectedSize) {
   if (terrainTypes.size() == expectedSize) {
     m_terrainTypes = terrainTypes;
     m_terrainTypes = terrainTypes;
   }
   }
-  
+
   m_hillEntrances.clear();
   m_hillEntrances.clear();
   m_hillEntrances.resize(expectedSize, false);
   m_hillEntrances.resize(expectedSize, false);
   m_hillWalkable.clear();
   m_hillWalkable.clear();
   m_hillWalkable.resize(expectedSize, true);
   m_hillWalkable.resize(expectedSize, true);
-  
+
   for (size_t i = 0; i < m_terrainTypes.size(); ++i) {
   for (size_t i = 0; i < m_terrainTypes.size(); ++i) {
     if (m_terrainTypes[i] == TerrainType::Hill) {
     if (m_terrainTypes[i] == TerrainType::Hill) {
       m_hillWalkable[i] = false;
       m_hillWalkable[i] = false;
     }
     }
   }
   }
-  
+
   m_riverSegments = rivers;
   m_riverSegments = rivers;
   m_bridges = bridges;
   m_bridges = bridges;
 }
 }

+ 1 - 2
game/map/terrain_service.cpp

@@ -96,8 +96,7 @@ void TerrainService::restoreFromSerialized(
     const std::vector<TerrainType> &terrainTypes,
     const std::vector<TerrainType> &terrainTypes,
     const std::vector<RiverSegment> &rivers, const std::vector<Bridge> &bridges,
     const std::vector<RiverSegment> &rivers, const std::vector<Bridge> &bridges,
     const BiomeSettings &biome) {
     const BiomeSettings &biome) {
-  m_heightMap =
-      std::make_unique<TerrainHeightMap>(width, height, tileSize);
+  m_heightMap = std::make_unique<TerrainHeightMap>(width, height, tileSize);
   m_heightMap->restoreFromData(heights, terrainTypes, rivers, bridges);
   m_heightMap->restoreFromData(heights, terrainTypes, rivers, bridges);
   m_biomeSettings = biome;
   m_biomeSettings = biome;
 }
 }

+ 4 - 4
game/units/factory.cpp

@@ -25,10 +25,10 @@ void registerBuiltInUnits(UnitFactoryRegistry &reg) {
                                               const SpawnParams &params) {
                                               const SpawnParams &params) {
     return Spearman::Create(world, params);
     return Spearman::Create(world, params);
   });
   });
-  reg.registerFactory("barracks", [](Engine::Core::World &world,
-                                     const SpawnParams &params) {
-    return Barracks::Create(world, params);
-  });
+  reg.registerFactory(
+      "barracks", [](Engine::Core::World &world, const SpawnParams &params) {
+        return Barracks::Create(world, params);
+      });
 }
 }
 
 
 } // namespace Units
 } // namespace Units

+ 2 - 1
game/units/spearman.cpp

@@ -22,7 +22,8 @@ static inline QVector3D teamColor(int ownerId) {
 namespace Game {
 namespace Game {
 namespace Units {
 namespace Units {
 
 
-Spearman::Spearman(Engine::Core::World &world) : Unit(world, TroopType::Spearman) {}
+Spearman::Spearman(Engine::Core::World &world)
+    : Unit(world, TroopType::Spearman) {}
 
 
 std::unique_ptr<Spearman> Spearman::Create(Engine::Core::World &world,
 std::unique_ptr<Spearman> Spearman::Create(Engine::Core::World &world,
                                            const SpawnParams &params) {
                                            const SpawnParams &params) {

+ 2 - 2
render/draw_queue.h

@@ -18,7 +18,7 @@ class Mesh;
 class Texture;
 class Texture;
 class Buffer;
 class Buffer;
 class Shader;
 class Shader;
-} // namespace Render::GL
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
@@ -329,4 +329,4 @@ private:
   std::vector<uint32_t> m_tempIndices;
   std::vector<uint32_t> m_tempIndices;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/draw_queue_soa.h

@@ -191,4 +191,4 @@ private:
   std::vector<TerrainChunkCmd> m_terrainChunkCmds;
   std::vector<TerrainChunkCmd> m_terrainChunkCmds;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 3 - 5
render/entity/archer_renderer.cpp

@@ -133,8 +133,7 @@ public:
     }
     }
 
 
     if (anim.isAttacking && !anim.isInHoldMode) {
     if (anim.isAttacking && !anim.isInHoldMode) {
-      float attackCycleTime = 1.2f;
-      float attackPhase = fmod(anim.time * (1.0f / attackCycleTime), 1.0f);
+      float attackPhase = fmod(anim.time * ARCHER_INV_ATTACK_CYCLE_TIME, 1.0f);
 
 
       if (anim.isMelee) {
       if (anim.isMelee) {
         QVector3D restPos(0.25f, HP::SHOULDER_Y, 0.10f);
         QVector3D restPos(0.25f, HP::SHOULDER_Y, 0.10f);
@@ -264,8 +263,7 @@ public:
 
 
     float attackPhase = 0.0f;
     float attackPhase = 0.0f;
     if (anim.isAttacking && !anim.isMelee) {
     if (anim.isAttacking && !anim.isMelee) {
-      float attackCycleTime = 1.2f;
-      attackPhase = fmod(anim.time * (1.0f / attackCycleTime), 1.0f);
+      attackPhase = fmod(anim.time * ARCHER_INV_ATTACK_CYCLE_TIME, 1.0f);
     }
     }
     drawBowAndArrow(ctx, pose, v, extras, anim.isAttacking && !anim.isMelee,
     drawBowAndArrow(ctx, pose, v, extras, anim.isAttacking && !anim.isMelee,
                     attackPhase, out);
                     attackPhase, out);
@@ -633,4 +631,4 @@ void registerArcherRenderer(Render::GL::EntityRendererRegistry &registry) {
       });
       });
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/entity/arrow_vfx_renderer.cpp

@@ -433,4 +433,4 @@ void registerArcherRenderer(Render::GL::EntityRendererRegistry &registry) {
       });
       });
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 3 - 3
render/entity/arrow_vfx_renderer.h

@@ -7,13 +7,13 @@ namespace Render {
 namespace GL {
 namespace GL {
 class Renderer;
 class Renderer;
 class ResourceManager;
 class ResourceManager;
-} // namespace GL
-} // namespace Render
+} 
+} 
 namespace Game {
 namespace Game {
 namespace Systems {
 namespace Systems {
 class ArrowSystem;
 class ArrowSystem;
 }
 }
-} // namespace Game
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 

+ 2 - 2
render/entity/barracks_renderer.cpp

@@ -683,10 +683,10 @@ static void drawBarracks(const DrawContext &p, ISubmitter &out) {
   drawSelectionFX(p, out);
   drawSelectionFX(p, out);
 }
 }
 
 
-} // namespace
+} 
 
 
 void registerBarracksRenderer(Render::GL::EntityRendererRegistry &registry) {
 void registerBarracksRenderer(Render::GL::EntityRendererRegistry &registry) {
   registry.registerRenderer("barracks", drawBarracks);
   registry.registerRenderer("barracks", drawBarracks);
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/entity/barracks_renderer.h

@@ -4,7 +4,7 @@ namespace Render {
 namespace GL {
 namespace GL {
 class EntityRendererRegistry;
 class EntityRendererRegistry;
 }
 }
-} // namespace Render
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 

+ 2 - 2
render/entity/horse_renderer.cpp

@@ -72,7 +72,7 @@ inline uint32_t colorHash(const QVector3D &c) {
   return v;
   return v;
 }
 }
 
 
-} // namespace
+} 
 
 
 HorseDimensions makeHorseDimensions(uint32_t seed) {
 HorseDimensions makeHorseDimensions(uint32_t seed) {
   HorseDimensions d;
   HorseDimensions d;
@@ -723,4 +723,4 @@ void HorseRenderer::render(const DrawContext &ctx, const AnimationInputs &anim,
   }
   }
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/entity/horse_renderer.h

@@ -76,4 +76,4 @@ public:
               const HorseProfile &profile, ISubmitter &out) const;
               const HorseProfile &profile, ISubmitter &out) const;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 3 - 5
render/entity/knight_renderer.cpp

@@ -79,8 +79,7 @@ public:
     float armAsymmetry = (hash01(seed ^ 0xDEF0u) - 0.5f) * 0.04f;
     float armAsymmetry = (hash01(seed ^ 0xDEF0u) - 0.5f) * 0.04f;
 
 
     if (anim.isAttacking && anim.isMelee) {
     if (anim.isAttacking && anim.isMelee) {
-      const float attackCycleTime = 0.6f;
-      float attackPhase = std::fmod(anim.time * (1.0f / attackCycleTime), 1.0f);
+      float attackPhase = std::fmod(anim.time * KNIGHT_INV_ATTACK_CYCLE_TIME, 1.0f);
 
 
       QVector3D restPos(0.20f, HP::SHOULDER_Y + 0.05f, 0.15f);
       QVector3D restPos(0.20f, HP::SHOULDER_Y + 0.05f, 0.15f);
       QVector3D preparePos(0.26f, HP::HEAD_TOP_Y + 0.18f, -0.06f);
       QVector3D preparePos(0.26f, HP::HEAD_TOP_Y + 0.18f, -0.06f);
@@ -151,8 +150,7 @@ public:
     bool isAttacking = anim.isAttacking && anim.isMelee;
     bool isAttacking = anim.isAttacking && anim.isMelee;
     float attackPhase = 0.0f;
     float attackPhase = 0.0f;
     if (isAttacking) {
     if (isAttacking) {
-      float attackCycleTime = 0.6f;
-      attackPhase = std::fmod(anim.time * (1.0f / attackCycleTime), 1.0f);
+      attackPhase = std::fmod(anim.time * KNIGHT_INV_ATTACK_CYCLE_TIME, 1.0f);
     }
     }
 
 
     drawSword(ctx, pose, v, extras, isAttacking, attackPhase, out);
     drawSword(ctx, pose, v, extras, isAttacking, attackPhase, out);
@@ -838,4 +836,4 @@ void registerKnightRenderer(Render::GL::EntityRendererRegistry &registry) {
       });
       });
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 4 - 38
render/entity/mounted_knight_renderer.cpp

@@ -30,6 +30,7 @@
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
+
 using Render::Geom::clamp01;
 using Render::Geom::clamp01;
 using Render::Geom::clampf;
 using Render::Geom::clampf;
 using Render::Geom::coneFromTo;
 using Render::Geom::coneFromTo;
@@ -40,41 +41,6 @@ using Render::Geom::nlerp;
 using Render::Geom::smoothstep;
 using Render::Geom::smoothstep;
 using Render::Geom::sphereAt;
 using Render::Geom::sphereAt;
 
 
-static constexpr std::size_t MAX_EXTRAS_CACHE_SIZE = 10000;
-
-// Optimized math helpers - constexpr for compile-time evaluation
-static constexpr inline float easeInOutCubic(float t) noexcept {
-  const float clamped = (t < 0.0f) ? 0.0f : ((t > 1.0f) ? 1.0f : t);
-  return clamped < 0.5f ? 4.0f * clamped * clamped * clamped
-                        : 1.0f - std::pow(-2.0f * clamped + 2.0f, 3.0f) / 2.0f;
-}
-
-static constexpr inline float smoothstep(float a, float b, float x) noexcept {
-  const float t = (x - a) / (b - a);
-  const float clamped = (t < 0.0f) ? 0.0f : ((t > 1.0f) ? 1.0f : t);
-  return clamped * clamped * (3.0f - 2.0f * clamped);
-}
-
-static constexpr inline float lerp(float a, float b, float t) noexcept {
-  return a * (1.0f - t) + b * t;
-}
-
-// Frequently used constants
-static constexpr float ATTACK_CYCLE_TIME = 0.70f;
-static constexpr float INV_ATTACK_CYCLE_TIME = 1.0f / ATTACK_CYCLE_TIME;
-
-// Common color multipliers (computed at compile time where possible)
-static const QVector3D STEEL_TINT(0.95f, 0.96f, 1.0f);
-static const QVector3D BRASS_TINT(1.3f, 1.1f, 0.7f);
-static const QVector3D CHAINMAIL_TINT(0.85f, 0.88f, 0.92f);
-
-static inline QVector3D nlerp(const QVector3D &a, const QVector3D &b, float t) noexcept {
-  QVector3D v = a * (1.0f - t) + b * t;
-  if (v.lengthSquared() > 1e-6f)
-    v.normalize();
-  return v;
-}
-
 struct MountedKnightExtras {
 struct MountedKnightExtras {
   QVector3D metalColor;
   QVector3D metalColor;
   HorseProfile horseProfile;
   HorseProfile horseProfile;
@@ -163,7 +129,7 @@ public:
                             (pose.shoulderR.z() + restHandR.z()) * 0.5f);
                             (pose.shoulderR.z() + restHandR.z()) * 0.5f);
 
 
     if (anim.isAttacking && anim.isMelee) {
     if (anim.isAttacking && anim.isMelee) {
-      float attackPhase = std::fmod(anim.time * INV_ATTACK_CYCLE_TIME, 1.0f);
+      float attackPhase = std::fmod(anim.time * MOUNTED_KNIGHT_INV_ATTACK_CYCLE_TIME, 1.0f);
 
 
       QVector3D restPos = restHandR;
       QVector3D restPos = restHandR;
       QVector3D windupPos = QVector3D(
       QVector3D windupPos = QVector3D(
@@ -249,7 +215,7 @@ public:
     bool isAttacking = anim.isAttacking && anim.isMelee;
     bool isAttacking = anim.isAttacking && anim.isMelee;
     float attackPhase = 0.0f;
     float attackPhase = 0.0f;
     if (isAttacking) {
     if (isAttacking) {
-      attackPhase = std::fmod(anim.time * INV_ATTACK_CYCLE_TIME, 1.0f);
+      attackPhase = std::fmod(anim.time * MOUNTED_KNIGHT_INV_ATTACK_CYCLE_TIME, 1.0f);
     }
     }
 
 
     if (extras.hasSword) {
     if (extras.hasSword) {
@@ -779,4 +745,4 @@ void registerMountedKnightRenderer(
       });
       });
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/entity/registry.cpp

@@ -30,4 +30,4 @@ void registerBuiltInEntityRenderers(EntityRendererRegistry &registry) {
   registerBarracksRenderer(registry);
   registerBarracksRenderer(registry);
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 5 - 5
render/entity/registry.h

@@ -12,16 +12,16 @@ namespace Engine {
 namespace Core {
 namespace Core {
 class Entity;
 class Entity;
 class World;
 class World;
-} // namespace Core
-} // namespace Engine
+} 
+} 
 namespace Render {
 namespace Render {
 namespace GL {
 namespace GL {
 class ResourceManager;
 class ResourceManager;
 class Mesh;
 class Mesh;
 class Texture;
 class Texture;
 class Backend;
 class Backend;
-} // namespace GL
-} // namespace Render
+} 
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
@@ -49,4 +49,4 @@ private:
 
 
 void registerBuiltInEntityRenderers(EntityRendererRegistry &registry);
 void registerBuiltInEntityRenderers(EntityRendererRegistry &registry);
 
 
-} // namespace Render::GL
+} 

+ 30 - 0
render/entity/renderer_constants.h

@@ -1,9 +1,39 @@
 #pragma once
 #pragma once
 
 
+#include <QVector3D>
 #include <cstddef>
 #include <cstddef>
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
+
 static constexpr std::size_t MAX_EXTRAS_CACHE_SIZE = 10000;
 static constexpr std::size_t MAX_EXTRAS_CACHE_SIZE = 10000;
 
 
+
+static constexpr float MOUNTED_KNIGHT_ATTACK_CYCLE_TIME = 0.70f;
+static constexpr float MOUNTED_KNIGHT_INV_ATTACK_CYCLE_TIME = 1.0f / MOUNTED_KNIGHT_ATTACK_CYCLE_TIME;
+
+static constexpr float SPEARMAN_ATTACK_CYCLE_TIME = 0.80f;
+static constexpr float SPEARMAN_INV_ATTACK_CYCLE_TIME = 1.0f / SPEARMAN_ATTACK_CYCLE_TIME;
+
+static constexpr float KNIGHT_ATTACK_CYCLE_TIME = 0.60f;
+static constexpr float KNIGHT_INV_ATTACK_CYCLE_TIME = 1.0f / KNIGHT_ATTACK_CYCLE_TIME;
+
+static constexpr float ARCHER_ATTACK_CYCLE_TIME = 1.20f;
+static constexpr float ARCHER_INV_ATTACK_CYCLE_TIME = 1.0f / ARCHER_ATTACK_CYCLE_TIME;
+
+
+
+static const QVector3D STEEL_TINT(0.95f, 0.96f, 1.0f);
+static const QVector3D IRON_TINT(0.88f, 0.90f, 0.92f);
+
+
+static const QVector3D BRASS_TINT(1.3f, 1.1f, 0.7f);
+
+
+static const QVector3D CHAINMAIL_TINT(0.85f, 0.88f, 0.92f);
+
+
+static const QVector3D DARK_METAL(0.15f, 0.15f, 0.15f);
+static const QVector3D VISOR_COLOR(0.1f, 0.1f, 0.1f);
+
 }
 }

+ 4 - 30
render/entity/spearman_renderer.cpp

@@ -29,6 +29,7 @@
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
+
 using Render::Geom::clamp01;
 using Render::Geom::clamp01;
 using Render::Geom::clampf;
 using Render::Geom::clampf;
 using Render::Geom::coneFromTo;
 using Render::Geom::coneFromTo;
@@ -38,33 +39,6 @@ using Render::Geom::lerp;
 using Render::Geom::smoothstep;
 using Render::Geom::smoothstep;
 using Render::Geom::sphereAt;
 using Render::Geom::sphereAt;
 
 
-static constexpr std::size_t MAX_EXTRAS_CACHE_SIZE = 10000;
-
-// Optimized math helpers - constexpr for compile-time evaluation
-static constexpr inline float easeInOutCubic(float t) noexcept {
-  const float clamped = (t < 0.0f) ? 0.0f : ((t > 1.0f) ? 1.0f : t);
-  return clamped < 0.5f ? 4.0f * clamped * clamped * clamped
-                        : 1.0f - std::pow(-2.0f * clamped + 2.0f, 3.0f) / 2.0f;
-}
-
-static constexpr inline float smoothstep(float a, float b, float x) noexcept {
-  const float t = (x - a) / (b - a);
-  const float clamped = (t < 0.0f) ? 0.0f : ((t > 1.0f) ? 1.0f : t);
-  return clamped * clamped * (3.0f - 2.0f * clamped);
-}
-
-static constexpr inline float lerp(float a, float b, float t) noexcept {
-  return a * (1.0f - t) + b * t;
-}
-
-// Frequently used constants
-static constexpr float ATTACK_CYCLE_TIME = 0.80f;
-static constexpr float INV_ATTACK_CYCLE_TIME = 1.0f / ATTACK_CYCLE_TIME;
-
-// Common color multipliers
-static const QVector3D IRON_TINT(0.88f, 0.90f, 0.92f);
-static const QVector3D DARK_METAL(0.15f, 0.15f, 0.15f);
-
 struct SpearmanExtras {
 struct SpearmanExtras {
   QVector3D spearShaftColor;
   QVector3D spearShaftColor;
   QVector3D spearheadColor;
   QVector3D spearheadColor;
@@ -155,7 +129,7 @@ public:
                     QVector3D(-0.08f, -0.12f, 0.05f);
                     QVector3D(-0.08f, -0.12f, 0.05f);
 
 
     } else if (anim.isAttacking && anim.isMelee && !anim.isInHoldMode) {
     } else if (anim.isAttacking && anim.isMelee && !anim.isInHoldMode) {
-      float attackPhase = std::fmod(anim.time * INV_ATTACK_CYCLE_TIME, 1.0f);
+      float attackPhase = std::fmod(anim.time * SPEARMAN_INV_ATTACK_CYCLE_TIME, 1.0f);
 
 
       QVector3D guardPos(0.28f, HP::SHOULDER_Y + 0.05f, 0.25f);
       QVector3D guardPos(0.28f, HP::SHOULDER_Y + 0.05f, 0.25f);
       QVector3D preparePos(0.35f, HP::SHOULDER_Y + 0.08f, 0.05f);
       QVector3D preparePos(0.35f, HP::SHOULDER_Y + 0.08f, 0.05f);
@@ -236,7 +210,7 @@ public:
     bool isAttacking = anim.isAttacking && anim.isMelee;
     bool isAttacking = anim.isAttacking && anim.isMelee;
     float attackPhase = 0.0f;
     float attackPhase = 0.0f;
     if (isAttacking) {
     if (isAttacking) {
-      attackPhase = std::fmod(anim.time * INV_ATTACK_CYCLE_TIME, 1.0f);
+      attackPhase = std::fmod(anim.time * SPEARMAN_INV_ATTACK_CYCLE_TIME, 1.0f);
     }
     }
 
 
     drawSpear(ctx, pose, v, extras, anim, isAttacking, attackPhase, out);
     drawSpear(ctx, pose, v, extras, anim, isAttacking, attackPhase, out);
@@ -467,4 +441,4 @@ void registerSpearmanRenderer(Render::GL::EntityRendererRegistry &registry) {
       });
       });
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 3 - 3
render/geom/arrow.cpp

@@ -82,7 +82,7 @@ GL::Mesh *Arrow::get() {
   return mesh;
   return mesh;
 }
 }
 
 
-} // namespace Geom
+} 
 
 
 namespace GL {
 namespace GL {
 
 
@@ -129,5 +129,5 @@ void renderArrows(Renderer *renderer, ResourceManager *resources,
   }
   }
 }
 }
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 5 - 5
render/geom/arrow.h

@@ -10,23 +10,23 @@ class Arrow {
 public:
 public:
   static GL::Mesh *get();
   static GL::Mesh *get();
 };
 };
-} // namespace Geom
+} 
 
 
 namespace GL {
 namespace GL {
 class Renderer;
 class Renderer;
 class ResourceManager;
 class ResourceManager;
-} // namespace GL
-} // namespace Render
+} 
+} 
 
 
 namespace Game {
 namespace Game {
 namespace Systems {
 namespace Systems {
 class ArrowSystem;
 class ArrowSystem;
 }
 }
-} // namespace Game
+} 
 
 
 namespace Render {
 namespace Render {
 namespace GL {
 namespace GL {
 void renderArrows(Renderer *renderer, ResourceManager *resources,
 void renderArrows(Renderer *renderer, ResourceManager *resources,
                   const Game::Systems::ArrowSystem &arrowSystem);
                   const Game::Systems::ArrowSystem &arrowSystem);
 }
 }
-} // namespace Render
+} 

+ 2 - 2
render/geom/flag.cpp

@@ -30,5 +30,5 @@ Flag::FlagMatrices Flag::create(float worldX, float worldZ,
   return result;
   return result;
 }
 }
 
 
-} // namespace Geom
-} // namespace Render
+} 
+} 

+ 2 - 2
render/geom/flag.h

@@ -23,5 +23,5 @@ public:
          float scale = 1.0f);
          float scale = 1.0f);
 };
 };
 
 
-} // namespace Geom
-} // namespace Render
+} 
+} 

+ 15 - 11
render/geom/math_utils.h

@@ -21,28 +21,32 @@ inline QVector3D clampVec(const QVector3D &c, float minVal, float maxVal) {
                    clampf(c.z(), minVal, maxVal));
                    clampf(c.z(), minVal, maxVal));
 }
 }
 
 
-inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; }
 
 
-inline QVector3D lerp(const QVector3D &a, const QVector3D &b, float t) {
+constexpr inline float lerp(float a, float b, float t) noexcept { 
+  return a * (1.0f - t) + b * t; 
+}
+
+inline QVector3D lerp(const QVector3D &a, const QVector3D &b, float t) noexcept {
   return a * (1.0f - t) + b * t;
   return a * (1.0f - t) + b * t;
 }
 }
 
 
-inline float easeInOutCubic(float t) {
-  t = clamp01(t);
-  return t < 0.5f ? 4.0f * t * t * t
-                  : 1.0f - std::pow(-2.0f * t + 2.0f, 3.0f) / 2.0f;
+constexpr inline float easeInOutCubic(float t) noexcept {
+  const float clamped = (t < 0.0f) ? 0.0f : ((t > 1.0f) ? 1.0f : t);
+  return clamped < 0.5f ? 4.0f * clamped * clamped * clamped
+                        : 1.0f - std::pow(-2.0f * clamped + 2.0f, 3.0f) / 2.0f;
 }
 }
 
 
-inline float smoothstep(float a, float b, float x) {
-  x = clamp01((x - a) / (b - a));
-  return x * x * (3.0f - 2.0f * x);
+constexpr inline float smoothstep(float a, float b, float x) noexcept {
+  const float t = (x - a) / (b - a);
+  const float clamped = (t < 0.0f) ? 0.0f : ((t > 1.0f) ? 1.0f : t);
+  return clamped * clamped * (3.0f - 2.0f * clamped);
 }
 }
 
 
-inline QVector3D nlerp(const QVector3D &a, const QVector3D &b, float t) {
+inline QVector3D nlerp(const QVector3D &a, const QVector3D &b, float t) noexcept {
   QVector3D v = a * (1.0f - t) + b * t;
   QVector3D v = a * (1.0f - t) + b * t;
   if (v.lengthSquared() > 1e-6f)
   if (v.lengthSquared() > 1e-6f)
     v.normalize();
     v.normalize();
   return v;
   return v;
 }
 }
 
 
-} // namespace Render::Geom
+} 

+ 1 - 1
render/geom/patrol_flags.cpp

@@ -71,4 +71,4 @@ void renderPatrolFlags(Renderer *renderer, ResourceManager *resources,
   }
   }
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/geom/patrol_flags.h

@@ -9,7 +9,7 @@ class World;
 namespace Render::GL {
 namespace Render::GL {
 class Renderer;
 class Renderer;
 class ResourceManager;
 class ResourceManager;
-} // namespace Render::GL
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 

+ 1 - 1
render/geom/selection_disc.cpp

@@ -35,4 +35,4 @@ Render::GL::Mesh *SelectionDisc::get() {
   return s_mesh.get();
   return s_mesh.get();
 }
 }
 
 
-} // namespace Render::Geom
+} 

+ 1 - 1
render/geom/selection_disc.h

@@ -13,4 +13,4 @@ private:
   static std::unique_ptr<Render::GL::Mesh> s_mesh;
   static std::unique_ptr<Render::GL::Mesh> s_mesh;
 };
 };
 
 
-} // namespace Render::Geom
+} 

+ 1 - 1
render/geom/selection_ring.cpp

@@ -42,4 +42,4 @@ Render::GL::Mesh *SelectionRing::get() {
   return s_mesh.get();
   return s_mesh.get();
 }
 }
 
 
-} // namespace Render::Geom
+} 

+ 1 - 1
render/geom/selection_ring.h

@@ -13,4 +13,4 @@ private:
   static std::unique_ptr<Render::GL::Mesh> s_mesh;
   static std::unique_ptr<Render::GL::Mesh> s_mesh;
 };
 };
 
 
-} // namespace Render::Geom
+} 

+ 2 - 2
render/geom/transforms.cpp

@@ -9,7 +9,7 @@ const QVector3D kYAxis(0, 1, 0);
 const float kRadToDeg = 57.2957795131f;
 const float kRadToDeg = 57.2957795131f;
 const float kEpsilon = 1e-6f;
 const float kEpsilon = 1e-6f;
 const float kEpsilonSq = kEpsilon * kEpsilon;
 const float kEpsilonSq = kEpsilon * kEpsilon;
-} // namespace
+} 
 
 
 QMatrix4x4 cylinderBetween(const QVector3D &a, const QVector3D &b,
 QMatrix4x4 cylinderBetween(const QVector3D &a, const QVector3D &b,
                            float radius) {
                            float radius) {
@@ -136,4 +136,4 @@ QMatrix4x4 capsuleBetween(const QMatrix4x4 &parent, const QVector3D &a,
   return cylinderBetween(parent, a, b, radius);
   return cylinderBetween(parent, a, b, radius);
 }
 }
 
 
-} // namespace Render::Geom
+} 

+ 1 - 1
render/geom/transforms.h

@@ -57,4 +57,4 @@ inline QVector3D toQVector3D(const Render::Math::Vec3 &v) {
   return QVector3D(v.x, v.y, v.z);
   return QVector3D(v.x, v.y, v.z);
 }
 }
 
 
-} // namespace Render::Geom
+} 

+ 1 - 1
render/gl/backend.cpp

@@ -1745,4 +1745,4 @@ void Backend::shutdownPinePipeline() {
   m_pineIndexCount = 0;
   m_pineIndexCount = 0;
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/backend.h

@@ -314,4 +314,4 @@ private:
   float m_animationTime = 0.0f;
   float m_animationTime = 0.0f;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/gl/bootstrap.cpp

@@ -22,5 +22,5 @@ bool RenderBootstrap::initialize(Renderer &renderer, Camera &camera) {
   return true;
   return true;
 }
 }
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 2 - 2
render/gl/bootstrap.h

@@ -15,5 +15,5 @@ public:
   static bool initialize(Renderer &renderer, Camera &camera);
   static bool initialize(Renderer &renderer, Camera &camera);
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/gl/buffer.cpp

@@ -92,4 +92,4 @@ void VertexArray::setIndexBuffer(Buffer &buffer) {
   buffer.bind();
   buffer.bind();
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/buffer.h

@@ -47,4 +47,4 @@ private:
   int m_currentAttribIndex = 0;
   int m_currentAttribIndex = 0;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 13 - 13
render/gl/camera.cpp

@@ -87,7 +87,7 @@ inline float smoothApproach(float current, float target, float smoothness) {
          (target - current) * std::clamp(1.0f - smoothness, 0.01f, 0.99f);
          (target - current) * std::clamp(1.0f - smoothness, 0.01f, 0.99f);
 }
 }
 
 
-} // namespace
+} 
 
 
 Camera::Camera() { updateVectors(); }
 Camera::Camera() { updateVectors(); }
 
 
@@ -630,41 +630,41 @@ void Camera::computeYawPitchFromOffset(const QVector3D &off, float &yawDeg,
 }
 }
 
 
 bool Camera::isInFrustum(const QVector3D &center, float radius) const {
 bool Camera::isInFrustum(const QVector3D &center, float radius) const {
-  // Simple frustum culling using sphere-frustum test
-  // Extract frustum planes from view-projection matrix
+  
+  
   QMatrix4x4 vp = getViewProjectionMatrix();
   QMatrix4x4 vp = getViewProjectionMatrix();
   
   
-  // Frustum planes (left, right, bottom, top, near, far)
-  // In clip space, planes are: x=-w, x=w, y=-w, y=w, z=-w, z=w
+  
+  
   float m[16];
   float m[16];
   const float *data = vp.constData();
   const float *data = vp.constData();
   for (int i = 0; i < 16; ++i) m[i] = data[i];
   for (int i = 0; i < 16; ++i) m[i] = data[i];
   
   
-  // Left plane: m03 + m00, m13 + m10, m23 + m20, m33 + m30
+  
   QVector3D leftN(m[3] + m[0], m[7] + m[4], m[11] + m[8]);
   QVector3D leftN(m[3] + m[0], m[7] + m[4], m[11] + m[8]);
   float leftD = m[15] + m[12];
   float leftD = m[15] + m[12];
   
   
-  // Right plane: m03 - m00, m13 - m10, m23 - m20, m33 - m30
+  
   QVector3D rightN(m[3] - m[0], m[7] - m[4], m[11] - m[8]);
   QVector3D rightN(m[3] - m[0], m[7] - m[4], m[11] - m[8]);
   float rightD = m[15] - m[12];
   float rightD = m[15] - m[12];
   
   
-  // Bottom plane: m03 + m01, m13 + m11, m23 + m21, m33 + m31
+  
   QVector3D bottomN(m[3] + m[1], m[7] + m[5], m[11] + m[9]);
   QVector3D bottomN(m[3] + m[1], m[7] + m[5], m[11] + m[9]);
   float bottomD = m[15] + m[13];
   float bottomD = m[15] + m[13];
   
   
-  // Top plane: m03 - m01, m13 - m11, m23 - m21, m33 - m31
+  
   QVector3D topN(m[3] - m[1], m[7] - m[5], m[11] - m[9]);
   QVector3D topN(m[3] - m[1], m[7] - m[5], m[11] - m[9]);
   float topD = m[15] - m[13];
   float topD = m[15] - m[13];
   
   
-  // Near plane: m03 + m02, m13 + m12, m23 + m22, m33 + m32
+  
   QVector3D nearN(m[3] + m[2], m[7] + m[6], m[11] + m[10]);
   QVector3D nearN(m[3] + m[2], m[7] + m[6], m[11] + m[10]);
   float nearD = m[15] + m[14];
   float nearD = m[15] + m[14];
   
   
-  // Far plane: m03 - m02, m13 - m12, m23 - m22, m33 - m32
+  
   QVector3D farN(m[3] - m[2], m[7] - m[6], m[11] - m[10]);
   QVector3D farN(m[3] - m[2], m[7] - m[6], m[11] - m[10]);
   float farD = m[15] - m[14];
   float farD = m[15] - m[14];
   
   
-  // Test sphere against each plane
+  
   auto testPlane = [&center, radius](const QVector3D &n, float d) -> bool {
   auto testPlane = [&center, radius](const QVector3D &n, float d) -> bool {
     float len = n.length();
     float len = n.length();
     if (len < 1e-6f) return true;
     if (len < 1e-6f) return true;
@@ -677,4 +677,4 @@ bool Camera::isInFrustum(const QVector3D &center, float radius) const {
          testPlane(nearN, nearD) && testPlane(farN, farD);
          testPlane(nearN, nearD) && testPlane(farN, farD);
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/camera.h

@@ -114,4 +114,4 @@ private:
                                  float &pitchDeg) const;
                                  float &pitchDeg) const;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/mesh.cpp

@@ -122,4 +122,4 @@ Mesh *createPlaneMesh(float width, float height, int subdivisions) {
   return new Mesh(vertices, indices);
   return new Mesh(vertices, indices);
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/mesh.h

@@ -39,4 +39,4 @@ Mesh *createQuadMesh();
 Mesh *createCubeMesh();
 Mesh *createCubeMesh();
 Mesh *createPlaneMesh(float width, float height, int subdivisions = 1);
 Mesh *createPlaneMesh(float width, float height, int subdivisions = 1);
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/persistent_buffer.h

@@ -147,4 +147,4 @@ private:
   int m_currentFrame = 0;
   int m_currentFrame = 0;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/gl/primitives.cpp

@@ -466,7 +466,7 @@ Mesh *createUnitTorsoMesh(int radialSegments, int heightSegments) {
   return new Mesh(v, idx);
   return new Mesh(v, idx);
 }
 }
 
 
-} // namespace
+} 
 
 
 Mesh *getUnitCylinder(int radialSegments) {
 Mesh *getUnitCylinder(int radialSegments) {
   static std::unique_ptr<Mesh> s_mesh(createUnitCylinderMesh(radialSegments));
   static std::unique_ptr<Mesh> s_mesh(createUnitCylinderMesh(radialSegments));
@@ -496,4 +496,4 @@ Mesh *getUnitTorso(int radialSegments, int heightSegments) {
   return s_mesh.get();
   return s_mesh.get();
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/primitives.h

@@ -15,4 +15,4 @@ Mesh *getUnitCapsule(int radialSegments = 32, int heightSegments = 1);
 
 
 Mesh *getUnitTorso(int radialSegments = 32, int heightSegments = 8);
 Mesh *getUnitTorso(int radialSegments = 32, int heightSegments = 8);
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/resources.cpp

@@ -20,4 +20,4 @@ bool ResourceManager::initialize() {
   return true;
   return true;
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/resources.h

@@ -30,4 +30,4 @@ private:
   std::unique_ptr<Texture> m_whiteTexture;
   std::unique_ptr<Texture> m_whiteTexture;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/shader.cpp

@@ -214,4 +214,4 @@ bool Shader::linkProgram(GLuint vertexShader, GLuint fragmentShader) {
   return true;
   return true;
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/shader.h

@@ -55,4 +55,4 @@ private:
   std::unordered_map<std::string, UniformHandle> m_uniformCache;
   std::unordered_map<std::string, UniformHandle> m_uniformCache;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/shader_cache.h

@@ -139,4 +139,4 @@ private:
   std::unordered_map<QString, std::unique_ptr<Shader>> m_cache;
   std::unordered_map<QString, std::unique_ptr<Shader>> m_cache;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/state_scopes.h

@@ -60,4 +60,4 @@ struct DepthTestScope {
       glDisable(GL_DEPTH_TEST);
       glDisable(GL_DEPTH_TEST);
   }
   }
 };
 };
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/texture.cpp

@@ -129,4 +129,4 @@ GLenum Texture::getGLWrap(Wrap wrap) const {
   return GL_REPEAT;
   return GL_REPEAT;
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 1 - 1
render/gl/texture.h

@@ -39,4 +39,4 @@ private:
   GLenum getGLWrap(Wrap wrap) const;
   GLenum getGLWrap(Wrap wrap) const;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/biome_renderer.cpp

@@ -66,7 +66,7 @@ inline int sectionFor(Game::Map::TerrainType type) {
   }
   }
 }
 }
 
 
-} // namespace
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
@@ -486,4 +486,4 @@ void BiomeRenderer::generateGrassInstances() {
   }
   }
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/biome_renderer.h

@@ -46,5 +46,5 @@ private:
   bool m_grassInstancesDirty = false;
   bool m_grassInstancesDirty = false;
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/bridge_renderer.cpp

@@ -240,4 +240,4 @@ void BridgeRenderer::submit(Renderer &renderer, ResourceManager *resources) {
   renderer.setCurrentShader(nullptr);
   renderer.setCurrentShader(nullptr);
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/bridge_renderer.h

@@ -29,5 +29,5 @@ private:
   std::vector<std::unique_ptr<Mesh>> m_meshes;
   std::vector<std::unique_ptr<Mesh>> m_meshes;
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/fog_renderer.cpp

@@ -73,4 +73,4 @@ void FogRenderer::buildChunks() {
   }
   }
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/fog_renderer.h

@@ -41,5 +41,5 @@ private:
   std::vector<FogInstance> m_instances;
   std::vector<FogInstance> m_instances;
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/grass_gpu.h

@@ -22,4 +22,4 @@ struct GrassBatchParams {
   float pad2{0.0f};
   float pad2{0.0f};
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 3 - 3
render/ground/ground_renderer.cpp

@@ -15,7 +15,7 @@ inline QVector3D saturate(const QVector3D &c) {
   return QVector3D(std::clamp(c.x(), 0.0f, 1.0f), std::clamp(c.y(), 0.0f, 1.0f),
   return QVector3D(std::clamp(c.x(), 0.0f, 1.0f), std::clamp(c.y(), 0.0f, 1.0f),
                    std::clamp(c.z(), 0.0f, 1.0f));
                    std::clamp(c.z(), 0.0f, 1.0f));
 }
 }
-} // namespace
+} 
 
 
 static QVector3D clamp01(const QVector3D &c) { return saturate(c); }
 static QVector3D clamp01(const QVector3D &c) { return saturate(c); }
 
 
@@ -149,5 +149,5 @@ void GroundRenderer::submit(Renderer &renderer, ResourceManager *resources) {
   renderer.grid(m_model, m_color, cell, 0.06f, extent);
   renderer.grid(m_model, m_color, cell, 0.06f, extent);
 }
 }
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 2 - 2
render/ground/ground_renderer.h

@@ -79,5 +79,5 @@ private:
   }
   }
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/pine_gpu.h

@@ -19,4 +19,4 @@ struct PineBatchParams {
   float windSpeed = 0.5f;
   float windSpeed = 0.5f;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/pine_renderer.cpp

@@ -53,7 +53,7 @@ inline float valueNoise(float x, float z, uint32_t seed) {
   return v0 * (1.0f - fz) + v1 * fz;
   return v0 * (1.0f - fz) + v1 * fz;
 }
 }
 
 
-} // namespace
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
@@ -280,4 +280,4 @@ void PineRenderer::generatePineInstances() {
   m_pineInstancesDirty = m_pineInstanceCount > 0;
   m_pineInstancesDirty = m_pineInstanceCount > 0;
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/pine_renderer.h

@@ -44,5 +44,5 @@ private:
   bool m_pineInstancesDirty = false;
   bool m_pineInstancesDirty = false;
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/plant_gpu.h

@@ -20,4 +20,4 @@ struct PlantBatchParams {
   float pad1 = 0.0f;
   float pad1 = 0.0f;
 };
 };
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/plant_renderer.cpp

@@ -53,7 +53,7 @@ inline float valueNoise(float x, float z, uint32_t salt = 0u) {
   return nx0 * (1 - tz) + nx1 * tz;
   return nx0 * (1 - tz) + nx1 * tz;
 }
 }
 
 
-} // namespace
+} 
 
 
 namespace Render::GL {
 namespace Render::GL {
 
 
@@ -360,4 +360,4 @@ void PlantRenderer::generatePlantInstances() {
   m_plantInstancesDirty = m_plantInstanceCount > 0;
   m_plantInstancesDirty = m_plantInstanceCount > 0;
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/plant_renderer.h

@@ -45,5 +45,5 @@ private:
   bool m_plantInstancesDirty = false;
   bool m_plantInstancesDirty = false;
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/river_renderer.cpp

@@ -218,4 +218,4 @@ void RiverRenderer::submit(Renderer &renderer, ResourceManager *resources) {
   renderer.setCurrentShader(nullptr);
   renderer.setCurrentShader(nullptr);
 }
 }
 
 
-} // namespace Render::GL
+} 

+ 2 - 2
render/ground/river_renderer.h

@@ -30,5 +30,5 @@ private:
   std::vector<std::unique_ptr<Mesh>> m_meshes;
   std::vector<std::unique_ptr<Mesh>> m_meshes;
 };
 };
 
 
-} // namespace GL
-} // namespace Render
+} 
+} 

+ 1 - 1
render/ground/riverbank_asset_gpu.h

@@ -18,4 +18,4 @@ struct RiverbankAssetBatchParams {
   float time{0.0f};
   float time{0.0f};
 };
 };
 
 
-} // namespace Render::GL
+} 

Some files were not shown because too many files changed in this diff