diff --git a/CMakeLists.txt b/CMakeLists.txt index a851bdd..101f88b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,11 +118,11 @@ find_package(glm CONFIG REQUIRED) if(BUILD_SDL3_APP) add_executable(sdl3_app src/main.cpp - src/core/platform.cpp src/di/service_registry.cpp src/events/event_bus.cpp src/services/impl/json_config_service.cpp src/services/impl/logger_service.cpp + src/services/impl/platform_service.cpp src/services/impl/script_engine_service.cpp src/services/impl/scene_script_service.cpp src/services/impl/shader_script_service.cpp @@ -148,7 +148,6 @@ if(BUILD_SDL3_APP) src/controllers/lifecycle_controller.cpp src/app/service_based_app.cpp src/gui/gui_renderer.cpp - src/core/vulkan_utils.cpp src/script/script_engine.cpp src/script/physics_bridge.cpp src/script/lua_helpers.cpp @@ -178,7 +177,7 @@ enable_testing() add_executable(script_engine_tests tests/test_cube_script.cpp - src/core/platform.cpp + src/services/impl/platform_service.cpp src/script/script_engine.cpp src/script/physics_bridge.cpp src/script/scene_manager.cpp diff --git a/src/app/service_based_app.cpp b/src/app/service_based_app.cpp index ce98e64..d13776a 100644 --- a/src/app/service_based_app.cpp +++ b/src/app/service_based_app.cpp @@ -1,8 +1,10 @@ #include "service_based_app.hpp" #include "events/event_bus.hpp" +#include "events/i_event_bus.hpp" #include "services/interfaces/i_window_service.hpp" #include "services/interfaces/i_graphics_service.hpp" #include "services/impl/json_config_service.hpp" +#include "services/impl/platform_service.hpp" #include "services/impl/sdl_window_service.hpp" #include "services/impl/sdl_input_service.hpp" #include "services/impl/vulkan_device_service.hpp" @@ -24,6 +26,7 @@ #include "services/impl/bullet_physics_service.hpp" #include "services/impl/crash_recovery_service.hpp" #include "services/impl/logger_service.hpp" +#include "services/interfaces/i_platform_service.hpp" #include #include @@ -173,8 +176,12 @@ void ServiceBasedApp::RegisterServices() { registry_.RegisterService( registry_.GetService()); + // Platform service (needed for SDL error enrichment) + registry_.RegisterService( + registry_.GetService()); + // Event bus (needed by window service) - registry_.RegisterService(); + registry_.RegisterService(); // Configuration service services::impl::RuntimeConfig runtimeConfig; @@ -185,11 +192,12 @@ void ServiceBasedApp::RegisterServices() { // Window service registry_.RegisterService( registry_.GetService(), - registry_.GetService()); + registry_.GetService(), + registry_.GetService()); // Input service registry_.RegisterService( - registry_.GetService(), + registry_.GetService(), registry_.GetService()); // Audio service (needed before script bindings execute) @@ -237,7 +245,7 @@ void ServiceBasedApp::RegisterServices() { // Swapchain service registry_.RegisterService( registry_.GetService(), - registry_.GetService(), + registry_.GetService(), registry_.GetService()); // Pipeline service @@ -273,7 +281,8 @@ void ServiceBasedApp::RegisterServices() { // GUI service registry_.RegisterService( - registry_.GetService()); + registry_.GetService(), + registry_.GetService()); // Physics service registry_.RegisterService( diff --git a/src/controllers/application_controller.cpp b/src/controllers/application_controller.cpp index 328b21a..c493076 100644 --- a/src/controllers/application_controller.cpp +++ b/src/controllers/application_controller.cpp @@ -6,7 +6,7 @@ #include "../services/interfaces/i_physics_service.hpp" #include "../services/interfaces/i_scene_service.hpp" #include "../services/interfaces/i_audio_service.hpp" -#include "../events/event_bus.hpp" +#include "../events/i_event_bus.hpp" #include "../events/event_types.hpp" #include @@ -60,7 +60,7 @@ void ApplicationController::HandleEvents() { } // Check for quit events - auto eventBus = registry_.GetService(); + auto eventBus = registry_.GetService(); if (eventBus) { // Process queued events eventBus->ProcessQueue(); diff --git a/src/core/platform.hpp b/src/core/platform.hpp deleted file mode 100644 index 3c12e6c..0000000 --- a/src/core/platform.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SDL3CPP_CORE_PLATFORM_HPP -#define SDL3CPP_CORE_PLATFORM_HPP - -#include -#include -#include - -namespace sdl3cpp::platform { - -// Platform detection -#ifdef _WIN32 - constexpr bool IsWindows = true; - constexpr bool IsUnix = false; -#else - constexpr bool IsWindows = false; - constexpr bool IsUnix = true; -#endif - -// Get user configuration directory (platform-specific) -std::optional GetUserConfigDirectory(); - -// Format platform-specific error messages -std::string GetPlatformError(); - -} // namespace sdl3cpp::platform - -#endif // SDL3CPP_CORE_PLATFORM_HPP diff --git a/src/core/vulkan_utils.cpp b/src/core/vulkan_utils.cpp deleted file mode 100644 index 8f3bb12..0000000 --- a/src/core/vulkan_utils.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "vulkan_utils.hpp" - -#include -#include -#include - -namespace sdl3cpp::vulkan::utils { - -namespace { - -uint32_t FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) { - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) { - if ((typeFilter & (1 << i)) && - (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - - throw std::runtime_error("Failed to find suitable memory type"); -} - -} // namespace - -VkExtent2D ChooseSwapExtent(VkSurfaceCapabilitiesKHR capabilities, SDL_Window* window) { - int width = 0; - int height = 0; - SDL_GetWindowSize(window, &width, &height); - - return VkExtent2D{ - static_cast(std::clamp(width, static_cast(capabilities.minImageExtent.width), - static_cast(capabilities.maxImageExtent.width))), - static_cast(std::clamp(height, static_cast(capabilities.minImageExtent.height), - static_cast(capabilities.maxImageExtent.height))) - }; -} - -void CreateBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage, - VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { - // Validate buffer size - if (size == 0) { - throw std::runtime_error("Cannot create buffer with size 0"); - } - - // Check available memory before allocating - VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); - - uint64_t totalAvailable = 0; - for (uint32_t i = 0; i < memProps.memoryHeapCount; ++i) { - if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { - totalAvailable += memProps.memoryHeaps[i].size; - } - } - - if (size > totalAvailable) { - throw std::runtime_error("Requested buffer size (" + - std::to_string(size / (1024 * 1024)) + " MB) exceeds available GPU memory (" + - std::to_string(totalAvailable / (1024 * 1024)) + " MB)"); - } - - VkBufferCreateInfo bufferInfo{}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VkResult createResult = vkCreateBuffer(device, &bufferInfo, nullptr, &buffer); - if (createResult != VK_SUCCESS) { - throw std::runtime_error("Failed to create buffer (error code: " + - std::to_string(createResult) + ", size: " + - std::to_string(size / 1024) + " KB)"); - } - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(device, buffer, &memRequirements); - - VkMemoryAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - - try { - allocInfo.memoryTypeIndex = - FindMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties); - } catch (const std::exception& e) { - vkDestroyBuffer(device, buffer, nullptr); - throw std::runtime_error(std::string("Failed to find suitable memory type: ") + e.what()); - } - - VkResult allocResult = vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory); - if (allocResult != VK_SUCCESS) { - vkDestroyBuffer(device, buffer, nullptr); - std::string errorMsg = "Failed to allocate buffer memory.\n"; - errorMsg += "Requested: " + std::to_string(memRequirements.size / (1024 * 1024)) + " MB\n"; - errorMsg += "Error code: " + std::to_string(allocResult) + "\n"; - if (allocResult == VK_ERROR_OUT_OF_DEVICE_MEMORY) { - errorMsg += "\nOut of GPU memory. Try:\n"; - errorMsg += "- Closing other GPU-intensive applications\n"; - errorMsg += "- Reducing window resolution\n"; - errorMsg += "- Upgrading GPU or system memory"; - } else if (allocResult == VK_ERROR_OUT_OF_HOST_MEMORY) { - errorMsg += "\nOut of system memory. Try:\n"; - errorMsg += "- Closing other applications\n"; - errorMsg += "- Adding more RAM to your system"; - } - throw std::runtime_error(errorMsg); - } - - vkBindBufferMemory(device, buffer, bufferMemory, 0); -} - -} // namespace sdl3cpp::vulkan::utils diff --git a/src/core/vulkan_utils.hpp b/src/core/vulkan_utils.hpp deleted file mode 100644 index e310f5b..0000000 --- a/src/core/vulkan_utils.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -namespace sdl3cpp::vulkan::utils { - -VkExtent2D ChooseSwapExtent(VkSurfaceCapabilitiesKHR capabilities, SDL_Window* window); - -void CreateBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage, - VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory); - -} // namespace sdl3cpp::vulkan::utils \ No newline at end of file diff --git a/src/events/event_bus.hpp b/src/events/event_bus.hpp index 17307db..aed439a 100644 --- a/src/events/event_bus.hpp +++ b/src/events/event_bus.hpp @@ -3,6 +3,7 @@ #include "../di/lifecycle.hpp" #include "event_listener.hpp" #include "event_types.hpp" +#include "i_event_bus.hpp" #include #include #include @@ -40,7 +41,7 @@ namespace sdl3cpp::events { * eventBus.ProcessQueue(); // Call once per frame * @endcode */ -class EventBus : public di::IInitializable, public di::IShutdownable { +class EventBus : public IEventBus, public di::IInitializable, public di::IShutdownable { public: EventBus() = default; ~EventBus() = default; @@ -60,7 +61,7 @@ public: * @param type The event type to subscribe to * @param listener The callback function to invoke */ - void Subscribe(EventType type, EventListener listener); + void Subscribe(EventType type, EventListener listener) override; /** * @brief Subscribe to all event types. @@ -70,7 +71,7 @@ public: * * @param listener The callback function to invoke for all events */ - void SubscribeAll(EventListener listener); + void SubscribeAll(EventListener listener) override; /** * @brief Publish an event synchronously. @@ -83,7 +84,7 @@ public: * * @param event The event to publish */ - void Publish(const Event& event); + void Publish(const Event& event) override; /** * @brief Publish an event asynchronously. @@ -96,7 +97,7 @@ public: * * @param event The event to publish */ - void PublishAsync(const Event& event); + void PublishAsync(const Event& event) override; /** * @brief Process all queued asynchronous events. @@ -106,14 +107,14 @@ public: * * Thread-safe: Can be called while other threads are calling PublishAsync(). */ - void ProcessQueue(); + void ProcessQueue() override; /** * @brief Remove all event listeners. * * Useful for testing or resetting the event bus state. */ - void ClearListeners(); + void ClearListeners() override; /** * @brief Get the number of listeners for a specific event type. @@ -121,14 +122,14 @@ public: * @param type The event type to query * @return The number of listeners subscribed to this event type */ - size_t GetListenerCount(EventType type) const; + size_t GetListenerCount(EventType type) const override; /** * @brief Get the number of global listeners. * * @return The number of listeners subscribed to all events */ - size_t GetGlobalListenerCount() const; + size_t GetGlobalListenerCount() const override; // IInitializable interface void Initialize() override {} diff --git a/src/events/i_event_bus.hpp b/src/events/i_event_bus.hpp new file mode 100644 index 0000000..06e5fc3 --- /dev/null +++ b/src/events/i_event_bus.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "event_listener.hpp" +#include "event_types.hpp" +#include + +namespace sdl3cpp::events { + +class IEventBus { +public: + virtual ~IEventBus() = default; + + virtual void Subscribe(EventType type, EventListener listener) = 0; + virtual void SubscribeAll(EventListener listener) = 0; + virtual void Publish(const Event& event) = 0; + virtual void PublishAsync(const Event& event) = 0; + virtual void ProcessQueue() = 0; + virtual void ClearListeners() = 0; + virtual size_t GetListenerCount(EventType type) const = 0; + virtual size_t GetGlobalListenerCount() const = 0; +}; + +} // namespace sdl3cpp::events diff --git a/src/gui/gui_renderer.cpp b/src/gui/gui_renderer.cpp index 09aa177..0deb239 100644 --- a/src/gui/gui_renderer.cpp +++ b/src/gui/gui_renderer.cpp @@ -1,7 +1,5 @@ #include "gui/gui_renderer.hpp" -#include "../core/vulkan_utils.hpp" - #include #include #include @@ -17,7 +15,6 @@ #include "../../third_party/font8x8_basic.h" namespace script = sdl3cpp::script; -namespace vulkan_utils = sdl3cpp::vulkan::utils; namespace sdl3cpp::gui { namespace { @@ -350,12 +347,14 @@ private: }; GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat swapchainFormat, - const std::filesystem::path& scriptDirectory) + const std::filesystem::path& scriptDirectory, + std::shared_ptr bufferService) : device_(device), physicalDevice_(physicalDevice), swapchainFormat_(swapchainFormat), scriptDirectory_(scriptDirectory), - canvas_(std::make_unique()) { + canvas_(std::make_unique()), + bufferService_(std::move(bufferService)) { } GuiRenderer::~GuiRenderer() { @@ -516,7 +515,10 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor if (size == 0) { return; } - vulkan_utils::CreateBuffer(device_, physicalDevice_, static_cast(size), + if (!bufferService_) { + throw std::runtime_error("Buffer service not available for GUI staging buffer"); + } + bufferService_->CreateBuffer(static_cast(size), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer_, stagingMemory_); diff --git a/src/gui/gui_renderer.hpp b/src/gui/gui_renderer.hpp index 34d84f1..72fe0b4 100644 --- a/src/gui/gui_renderer.hpp +++ b/src/gui/gui_renderer.hpp @@ -9,6 +9,7 @@ #include #include "script/gui_types.hpp" +#include "services/interfaces/i_buffer_service.hpp" namespace sdl3cpp::gui { @@ -28,7 +29,8 @@ struct ParsedSvg { class GuiRenderer { public: GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat swapchainFormat, - const std::filesystem::path& scriptDirectory); + const std::filesystem::path& scriptDirectory, + std::shared_ptr bufferService); ~GuiRenderer(); GuiRenderer(const GuiRenderer&) = delete; @@ -63,6 +65,7 @@ private: uint32_t canvasHeight_ = 0; std::unique_ptr canvas_; std::unordered_map svgCache_; + std::shared_ptr bufferService_; }; } // namespace sdl3cpp::gui diff --git a/src/main.cpp b/src/main.cpp index f94ae1f..e5af87a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,7 @@ #include "app/service_based_app.hpp" #include #include "services/interfaces/i_logger.hpp" -#include "core/platform.hpp" +#include "services/impl/platform_service.hpp" using namespace sdl3cpp::services; @@ -168,7 +168,8 @@ RuntimeConfig LoadRuntimeConfigFromJson(const std::filesystem::path& configPath, } std::optional GetDefaultConfigPath() { - if (auto dir = sdl3cpp::platform::GetUserConfigDirectory()) { + sdl3cpp::services::impl::PlatformService platformService; + if (auto dir = platformService.GetUserConfigDirectory()) { return *dir / "default_runtime.json"; } return std::nullopt; diff --git a/src/services/impl/buffer_service.cpp b/src/services/impl/buffer_service.cpp index 6df66ec..0bb1d68 100644 --- a/src/services/impl/buffer_service.cpp +++ b/src/services/impl/buffer_service.cpp @@ -1,7 +1,7 @@ #include "buffer_service.hpp" -#include "../../core/vulkan_utils.hpp" #include #include +#include namespace sdl3cpp::services::impl { @@ -97,7 +97,94 @@ void BufferService::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, auto device = deviceService_->GetDevice(); auto physicalDevice = deviceService_->GetPhysicalDevice(); - vulkan::utils::CreateBuffer(device, physicalDevice, size, usage, properties, buffer, bufferMemory); + if (logger_) { + logger_->Debug("Creating buffer with size " + std::to_string(size) + " bytes"); + } + + if (size == 0) { + if (logger_) { + logger_->Error("Cannot create buffer with size 0"); + } + throw std::runtime_error("Cannot create buffer with size 0"); + } + + VkPhysicalDeviceMemoryProperties memProps; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); + + uint64_t totalAvailable = 0; + for (uint32_t i = 0; i < memProps.memoryHeapCount; ++i) { + if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { + totalAvailable += memProps.memoryHeaps[i].size; + } + } + + if (size > totalAvailable) { + throw std::runtime_error("Requested buffer size (" + + std::to_string(size / (1024 * 1024)) + " MB) exceeds available GPU memory (" + + std::to_string(totalAvailable / (1024 * 1024)) + " MB)"); + } + + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkResult createResult = vkCreateBuffer(device, &bufferInfo, nullptr, &buffer); + if (createResult != VK_SUCCESS) { + throw std::runtime_error("Failed to create buffer (error code: " + + std::to_string(createResult) + ", size: " + + std::to_string(size / 1024) + " KB)"); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, buffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + + bool foundType = false; + for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) { + if ((memRequirements.memoryTypeBits & (1 << i)) && + (memProps.memoryTypes[i].propertyFlags & properties) == properties) { + allocInfo.memoryTypeIndex = i; + foundType = true; + if (logger_) { + logger_->Debug("Found suitable memory type: " + std::to_string(i)); + } + break; + } + } + + if (!foundType) { + vkDestroyBuffer(device, buffer, nullptr); + if (logger_) { + logger_->Error("Failed to find suitable memory type"); + } + throw std::runtime_error("Failed to find suitable memory type"); + } + + VkResult allocResult = vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory); + if (allocResult != VK_SUCCESS) { + vkDestroyBuffer(device, buffer, nullptr); + std::string errorMsg = "Failed to allocate buffer memory.\n"; + errorMsg += "Requested: " + std::to_string(memRequirements.size / (1024 * 1024)) + " MB\n"; + errorMsg += "Error code: " + std::to_string(allocResult) + "\n"; + if (allocResult == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + errorMsg += "\nOut of GPU memory. Try:\n"; + errorMsg += "- Closing other GPU-intensive applications\n"; + errorMsg += "- Reducing window resolution\n"; + errorMsg += "- Upgrading GPU or system memory"; + } else if (allocResult == VK_ERROR_OUT_OF_HOST_MEMORY) { + errorMsg += "\nOut of system memory. Try:\n"; + errorMsg += "- Closing other applications\n"; + errorMsg += "- Adding more RAM to your system"; + } + throw std::runtime_error(errorMsg); + } + + vkBindBufferMemory(device, buffer, bufferMemory, 0); } void BufferService::CleanupBuffers() { diff --git a/src/core/platform.cpp b/src/services/impl/platform_service.cpp similarity index 71% rename from src/core/platform.cpp rename to src/services/impl/platform_service.cpp index b534720..6fd188e 100644 --- a/src/core/platform.cpp +++ b/src/services/impl/platform_service.cpp @@ -1,14 +1,22 @@ -#include "core/platform.hpp" +#include "platform_service.hpp" #include +#include #ifdef _WIN32 #include #endif -namespace sdl3cpp::platform { +namespace sdl3cpp::services::impl { -std::optional GetUserConfigDirectory() { +PlatformService::PlatformService(std::shared_ptr logger) + : logger_(std::move(logger)) { +} + +std::optional PlatformService::GetUserConfigDirectory() const { + if (logger_) { + logger_->Trace("PlatformService", "GetUserConfigDirectory"); + } #ifdef _WIN32 if (const char* appData = std::getenv("APPDATA")) { return std::filesystem::path(appData) / "sdl3cpp"; @@ -25,8 +33,7 @@ std::optional GetUserConfigDirectory() { } #ifdef _WIN32 -namespace { -std::string FormatWin32Error(DWORD errorCode) { +std::string PlatformService::FormatWin32Error(unsigned long errorCode) const { if (errorCode == ERROR_SUCCESS) { return "ERROR_SUCCESS"; } @@ -44,7 +51,6 @@ std::string FormatWin32Error(DWORD errorCode) { std::string message; if (length > 0 && buffer != nullptr) { message = std::string(buffer, length); - // Remove trailing newlines while (!message.empty() && (message.back() == '\n' || message.back() == '\r')) { message.pop_back(); } @@ -54,10 +60,12 @@ std::string FormatWin32Error(DWORD errorCode) { } return message; } -} // anonymous namespace #endif -std::string GetPlatformError() { +std::string PlatformService::GetPlatformError() const { + if (logger_) { + logger_->Trace("PlatformService", "GetPlatformError"); + } #ifdef _WIN32 DWORD win32Error = ::GetLastError(); if (win32Error != ERROR_SUCCESS) { @@ -69,4 +77,4 @@ std::string GetPlatformError() { #endif } -} // namespace sdl3cpp::platform +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/platform_service.hpp b/src/services/impl/platform_service.hpp new file mode 100644 index 0000000..6e2055b --- /dev/null +++ b/src/services/impl/platform_service.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../interfaces/i_platform_service.hpp" +#include "../interfaces/i_logger.hpp" +#include + +namespace sdl3cpp::services::impl { + +class PlatformService : public IPlatformService { +public: + explicit PlatformService(std::shared_ptr logger = nullptr); + ~PlatformService() override = default; + + std::optional GetUserConfigDirectory() const override; + std::string GetPlatformError() const override; + +private: + std::shared_ptr logger_; +#ifdef _WIN32 + std::string FormatWin32Error(unsigned long errorCode) const; +#endif +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/sdl_input_service.cpp b/src/services/impl/sdl_input_service.cpp index d65fe7c..0ae2133 100644 --- a/src/services/impl/sdl_input_service.cpp +++ b/src/services/impl/sdl_input_service.cpp @@ -12,7 +12,7 @@ const std::unordered_map SdlInputService::kGuiKeyNames {SDLK_RALT, "ralt"} }; -SdlInputService::SdlInputService(std::shared_ptr eventBus, std::shared_ptr logger) +SdlInputService::SdlInputService(std::shared_ptr eventBus, std::shared_ptr logger) : eventBus_(std::move(eventBus)), logger_(logger) { // Subscribe to input events diff --git a/src/services/impl/sdl_input_service.hpp b/src/services/impl/sdl_input_service.hpp index f1a2218..452a6f7 100644 --- a/src/services/impl/sdl_input_service.hpp +++ b/src/services/impl/sdl_input_service.hpp @@ -3,7 +3,7 @@ #include "../interfaces/i_input_service.hpp" #include "../interfaces/i_gui_script_service.hpp" #include "../interfaces/i_logger.hpp" -#include "../../events/event_bus.hpp" +#include "../../events/i_event_bus.hpp" #include namespace sdl3cpp::services::impl { @@ -23,7 +23,7 @@ public: * * @param eventBus Event bus to subscribe to */ - explicit SdlInputService(std::shared_ptr eventBus, std::shared_ptr logger); + explicit SdlInputService(std::shared_ptr eventBus, std::shared_ptr logger); // IInputService interface void ProcessEvent(const SDL_Event& event) override; @@ -36,7 +36,7 @@ public: void UpdateGuiInput() override; private: - std::shared_ptr eventBus_; + std::shared_ptr eventBus_; std::shared_ptr logger_; InputState state_; script::GuiInputSnapshot guiInputSnapshot_; diff --git a/src/services/impl/sdl_window_service.cpp b/src/services/impl/sdl_window_service.cpp index 4b833d2..f6a3ecc 100644 --- a/src/services/impl/sdl_window_service.cpp +++ b/src/services/impl/sdl_window_service.cpp @@ -1,6 +1,5 @@ #include "sdl_window_service.hpp" #include "../interfaces/i_logger.hpp" -#include "../../core/platform.hpp" #include #include #include @@ -10,7 +9,7 @@ namespace sdl3cpp::services::impl { namespace { -std::string BuildSdlErrorMessage(const char* context) { +std::string BuildSdlErrorMessage(const char* context, const std::shared_ptr& platformService) { std::ostringstream oss; oss << context; const char* sdlError = SDL_GetError(); @@ -20,17 +19,19 @@ std::string BuildSdlErrorMessage(const char* context) { oss << ": (SDL_GetError returned an empty string)"; } - std::string platformError = sdl3cpp::platform::GetPlatformError(); - if (!platformError.empty() && platformError != "No platform error") { - oss << " [" << platformError << "]"; + if (platformService) { + std::string platformError = platformService->GetPlatformError(); + if (!platformError.empty() && platformError != "No platform error") { + oss << " [" << platformError << "]"; + } } return oss.str(); } -void ThrowSdlErrorIfFailed(bool success, const char* context) { +void ThrowSdlErrorIfFailed(bool success, const char* context, const std::shared_ptr& platformService) { if (!success) { - throw std::runtime_error(BuildSdlErrorMessage(context)); + throw std::runtime_error(BuildSdlErrorMessage(context, platformService)); } } @@ -45,8 +46,12 @@ void ShowErrorDialog(const char* title, const std::string& message) { } // namespace -SdlWindowService::SdlWindowService(std::shared_ptr logger, std::shared_ptr eventBus) - : logger_(std::move(logger)), eventBus_(std::move(eventBus)) { +SdlWindowService::SdlWindowService(std::shared_ptr logger, + std::shared_ptr platformService, + std::shared_ptr eventBus) + : logger_(std::move(logger)), + platformService_(std::move(platformService)), + eventBus_(std::move(eventBus)) { } SdlWindowService::~SdlWindowService() { @@ -101,7 +106,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) { // Initialize SDL here if not already initialized if (SDL_WasInit(0) == 0) { try { - ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed"); + ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed", platformService_); } catch (const std::exception& e) { ShowErrorDialog("SDL Initialization Failed", std::string("Failed to initialize SDL subsystems.\n\nError: ") + e.what()); @@ -109,7 +114,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) { } try { - ThrowSdlErrorIfFailed(SDL_Vulkan_LoadLibrary(nullptr), "SDL_Vulkan_LoadLibrary failed"); + ThrowSdlErrorIfFailed(SDL_Vulkan_LoadLibrary(nullptr), "SDL_Vulkan_LoadLibrary failed", platformService_); } catch (const std::exception& e) { ShowErrorDialog("Vulkan Library Load Failed", std::string("Failed to load Vulkan library. Make sure Vulkan drivers are installed.\n\nError: ") + e.what()); @@ -130,7 +135,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) { ); if (!window_) { - std::string errorMsg = BuildSdlErrorMessage("SDL_CreateWindow failed"); + std::string errorMsg = BuildSdlErrorMessage("SDL_CreateWindow failed", platformService_); ShowErrorDialog("Window Creation Failed", std::string("Failed to create application window.\n\nError: ") + errorMsg); throw std::runtime_error(errorMsg); diff --git a/src/services/impl/sdl_window_service.hpp b/src/services/impl/sdl_window_service.hpp index f681a3f..a7e93dd 100644 --- a/src/services/impl/sdl_window_service.hpp +++ b/src/services/impl/sdl_window_service.hpp @@ -2,8 +2,9 @@ #include "../interfaces/i_window_service.hpp" #include "../interfaces/i_logger.hpp" +#include "../interfaces/i_platform_service.hpp" #include "../../di/lifecycle.hpp" -#include "../../events/event_bus.hpp" +#include "../../events/i_event_bus.hpp" #include #include @@ -25,7 +26,9 @@ public: * @param logger Logger service for logging * @param eventBus Event bus for publishing window/input events */ - SdlWindowService(std::shared_ptr logger, std::shared_ptr eventBus); + SdlWindowService(std::shared_ptr logger, + std::shared_ptr platformService, + std::shared_ptr eventBus); ~SdlWindowService() override; @@ -47,7 +50,8 @@ public: private: std::shared_ptr logger_; - std::shared_ptr eventBus_; + std::shared_ptr platformService_; + std::shared_ptr eventBus_; SDL_Window* window_ = nullptr; bool shouldClose_ = false; bool initialized_ = false; diff --git a/src/services/impl/swapchain_service.cpp b/src/services/impl/swapchain_service.cpp index 04715a6..0934f80 100644 --- a/src/services/impl/swapchain_service.cpp +++ b/src/services/impl/swapchain_service.cpp @@ -5,7 +5,7 @@ namespace sdl3cpp::services::impl { SwapchainService::SwapchainService(std::shared_ptr deviceService, - std::shared_ptr eventBus, + std::shared_ptr eventBus, std::shared_ptr logger) : deviceService_(std::move(deviceService)), eventBus_(std::move(eventBus)), logger_(logger) { // Subscribe to window resize events diff --git a/src/services/impl/swapchain_service.hpp b/src/services/impl/swapchain_service.hpp index 27dcacb..a5c3960 100644 --- a/src/services/impl/swapchain_service.hpp +++ b/src/services/impl/swapchain_service.hpp @@ -4,7 +4,7 @@ #include "../interfaces/i_vulkan_device_service.hpp" #include "../interfaces/i_logger.hpp" #include "../../di/lifecycle.hpp" -#include "../../events/event_bus.hpp" +#include "../../events/i_event_bus.hpp" #include #include @@ -21,7 +21,7 @@ class SwapchainService : public ISwapchainService, public di::IShutdownable { public: explicit SwapchainService(std::shared_ptr deviceService, - std::shared_ptr eventBus, + std::shared_ptr eventBus, std::shared_ptr logger); ~SwapchainService() override; @@ -50,7 +50,7 @@ public: private: std::shared_ptr deviceService_; - std::shared_ptr eventBus_; + std::shared_ptr eventBus_; std::shared_ptr logger_; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; diff --git a/src/services/impl/vulkan_gui_service.cpp b/src/services/impl/vulkan_gui_service.cpp index 018d495..2b857ea 100644 --- a/src/services/impl/vulkan_gui_service.cpp +++ b/src/services/impl/vulkan_gui_service.cpp @@ -4,8 +4,10 @@ namespace sdl3cpp::services::impl { -VulkanGuiService::VulkanGuiService(std::shared_ptr logger) - : logger_(std::move(logger)) { +VulkanGuiService::VulkanGuiService(std::shared_ptr logger, + std::shared_ptr bufferService) + : logger_(std::move(logger)), + bufferService_(std::move(bufferService)) { } VulkanGuiService::~VulkanGuiService() { @@ -24,7 +26,7 @@ void VulkanGuiService::Initialize(VkDevice device, return; } - renderer_ = std::make_unique(device, physicalDevice, format, resourcePath); + renderer_ = std::make_unique(device, physicalDevice, format, resourcePath, bufferService_); initialized_ = true; logger_->Info("GUI service initialized"); diff --git a/src/services/impl/vulkan_gui_service.hpp b/src/services/impl/vulkan_gui_service.hpp index a3e2d93..8f894c2 100644 --- a/src/services/impl/vulkan_gui_service.hpp +++ b/src/services/impl/vulkan_gui_service.hpp @@ -1,6 +1,7 @@ #pragma once #include "../interfaces/i_gui_service.hpp" +#include "../interfaces/i_buffer_service.hpp" #include "../interfaces/i_logger.hpp" #include "../../gui/gui_renderer.hpp" #include "../../di/lifecycle.hpp" @@ -17,7 +18,8 @@ namespace sdl3cpp::services::impl { class VulkanGuiService : public IGuiService, public di::IShutdownable { public: - explicit VulkanGuiService(std::shared_ptr logger); + VulkanGuiService(std::shared_ptr logger, + std::shared_ptr bufferService); ~VulkanGuiService() override; // IGuiService interface @@ -38,6 +40,7 @@ public: private: std::shared_ptr logger_; + std::shared_ptr bufferService_; std::unique_ptr renderer_; bool initialized_ = false; }; diff --git a/src/services/interfaces/i_platform_service.hpp b/src/services/interfaces/i_platform_service.hpp new file mode 100644 index 0000000..f6c37ce --- /dev/null +++ b/src/services/interfaces/i_platform_service.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +namespace sdl3cpp::services { + +class IPlatformService { +public: + virtual ~IPlatformService() = default; + + virtual std::optional GetUserConfigDirectory() const = 0; + virtual std::string GetPlatformError() const = 0; +}; + +} // namespace sdl3cpp::services