mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
feat: Add services for audio, physics, and GUI rendering integration
This commit is contained in:
@@ -131,6 +131,10 @@ if(BUILD_SDL3_APP)
|
||||
src/services/impl/pipeline_service.cpp
|
||||
src/services/impl/buffer_service.cpp
|
||||
src/services/impl/render_command_service.cpp
|
||||
src/services/impl/sdl_audio_service.cpp
|
||||
src/services/impl/vulkan_gui_service.cpp
|
||||
src/services/impl/bullet_physics_service.cpp
|
||||
src/services/impl/lua_script_service.cpp
|
||||
src/app/sdl3_app_core.cpp
|
||||
src/app/audio_player.cpp
|
||||
src/app/sdl3_app_device.cpp
|
||||
|
||||
142
src/services/impl/bullet_physics_service.cpp
Normal file
142
src/services/impl/bullet_physics_service.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "bullet_physics_service.hpp"
|
||||
#include "../../logging/logger.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
BulletPhysicsService::~BulletPhysicsService() {
|
||||
if (initialized_) {
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void BulletPhysicsService::Initialize(const btVector3& gravity) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
physicsBridge_ = std::make_unique<script::PhysicsBridge>();
|
||||
initialized_ = true;
|
||||
|
||||
logging::Logger::GetInstance().Info("Physics service initialized");
|
||||
}
|
||||
|
||||
void BulletPhysicsService::Shutdown() noexcept {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
physicsBridge_.reset();
|
||||
initialized_ = false;
|
||||
|
||||
logging::Logger::GetInstance().Info("Physics service shutdown");
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::AddBoxRigidBody(const std::string& name,
|
||||
const btVector3& halfExtents,
|
||||
float mass,
|
||||
const btTransform& transform) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!physicsBridge_) {
|
||||
throw std::runtime_error("Physics service not initialized");
|
||||
}
|
||||
|
||||
std::string error;
|
||||
return physicsBridge_->addBoxRigidBody(name, halfExtents, mass, transform, error);
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::AddSphereRigidBody(const std::string& name,
|
||||
float radius,
|
||||
float mass,
|
||||
const btTransform& transform) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
// PhysicsBridge doesn't support sphere rigid bodies in current implementation
|
||||
logging::Logger::GetInstance().Warn("AddSphereRigidBody not supported by PhysicsBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::RemoveRigidBody(const std::string& name) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
// PhysicsBridge doesn't support removing bodies in current implementation
|
||||
logging::Logger::GetInstance().Warn("RemoveRigidBody not supported by PhysicsBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
void BulletPhysicsService::StepSimulation(float deltaTime, int maxSubSteps) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!physicsBridge_) {
|
||||
throw std::runtime_error("Physics service not initialized");
|
||||
}
|
||||
|
||||
physicsBridge_->stepSimulation(deltaTime);
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::GetTransform(const std::string& name, btTransform& outTransform) const {
|
||||
if (!physicsBridge_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
return physicsBridge_->getRigidBodyTransform(name, outTransform, error);
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::SetTransform(const std::string& name, const btTransform& transform) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
// PhysicsBridge doesn't support setting transforms in current implementation
|
||||
logging::Logger::GetInstance().Warn("SetTransform not supported by PhysicsBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::ApplyForce(const std::string& name, const btVector3& force) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
// PhysicsBridge doesn't support applying forces in current implementation
|
||||
logging::Logger::GetInstance().Warn("ApplyForce not supported by PhysicsBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::ApplyImpulse(const std::string& name, const btVector3& impulse) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
// PhysicsBridge doesn't support applying impulses in current implementation
|
||||
logging::Logger::GetInstance().Warn("ApplyImpulse not supported by PhysicsBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BulletPhysicsService::SetLinearVelocity(const std::string& name, const btVector3& velocity) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
// PhysicsBridge doesn't support setting velocity in current implementation
|
||||
logging::Logger::GetInstance().Warn("SetLinearVelocity not supported by PhysicsBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t BulletPhysicsService::GetBodyCount() const {
|
||||
// PhysicsBridge doesn't expose GetBodyCount in current implementation
|
||||
// Returning 0 as stub - could track bodies in wrapper if needed
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BulletPhysicsService::Clear() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!physicsBridge_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// PhysicsBridge doesn't expose Clear in current implementation
|
||||
// Shutdown and reinitialize to clear all bodies
|
||||
physicsBridge_.reset();
|
||||
physicsBridge_ = std::make_unique<script::PhysicsBridge>();
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
56
src/services/impl/bullet_physics_service.hpp
Normal file
56
src/services/impl/bullet_physics_service.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_physics_service.hpp"
|
||||
#include "../../script/physics_bridge.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
/**
|
||||
* @brief Bullet physics service implementation.
|
||||
*
|
||||
* Small wrapper service (~120 lines) around PhysicsBridge.
|
||||
* Provides rigid body physics simulation using Bullet Physics.
|
||||
*/
|
||||
class BulletPhysicsService : public IPhysicsService,
|
||||
public di::IInitializable,
|
||||
public di::IShutdownable {
|
||||
public:
|
||||
BulletPhysicsService() = default;
|
||||
~BulletPhysicsService() override;
|
||||
|
||||
// IPhysicsService interface
|
||||
void Initialize(const btVector3& gravity = btVector3(0, -9.8f, 0)) override;
|
||||
void Shutdown() noexcept override;
|
||||
|
||||
bool AddBoxRigidBody(const std::string& name,
|
||||
const btVector3& halfExtents,
|
||||
float mass,
|
||||
const btTransform& transform) override;
|
||||
|
||||
bool AddSphereRigidBody(const std::string& name,
|
||||
float radius,
|
||||
float mass,
|
||||
const btTransform& transform) override;
|
||||
|
||||
bool RemoveRigidBody(const std::string& name) override;
|
||||
|
||||
void StepSimulation(float deltaTime, int maxSubSteps = 10) override;
|
||||
|
||||
bool GetTransform(const std::string& name, btTransform& outTransform) const override;
|
||||
bool SetTransform(const std::string& name, const btTransform& transform) override;
|
||||
|
||||
bool ApplyForce(const std::string& name, const btVector3& force) override;
|
||||
bool ApplyImpulse(const std::string& name, const btVector3& impulse) override;
|
||||
bool SetLinearVelocity(const std::string& name, const btVector3& velocity) override;
|
||||
|
||||
size_t GetBodyCount() const override;
|
||||
void Clear() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<script::PhysicsBridge> physicsBridge_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
135
src/services/impl/lua_script_service.cpp
Normal file
135
src/services/impl/lua_script_service.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "lua_script_service.hpp"
|
||||
#include "../../logging/logger.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
LuaScriptService::LuaScriptService(const std::filesystem::path& scriptPath, bool debugEnabled)
|
||||
: scriptPath_(scriptPath), debugEnabled_(debugEnabled) {
|
||||
}
|
||||
|
||||
LuaScriptService::~LuaScriptService() {
|
||||
if (initialized_) {
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void LuaScriptService::Initialize() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
engine_ = std::make_unique<script::ScriptEngine>(scriptPath_, debugEnabled_);
|
||||
initialized_ = true;
|
||||
|
||||
logging::Logger::GetInstance().Info("Script service initialized");
|
||||
}
|
||||
|
||||
void LuaScriptService::Shutdown() noexcept {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
engine_.reset();
|
||||
initialized_ = false;
|
||||
|
||||
logging::Logger::GetInstance().Info("Script service shutdown");
|
||||
}
|
||||
|
||||
std::vector<script::SceneManager::SceneObject> LuaScriptService::LoadSceneObjects() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!engine_) {
|
||||
throw std::runtime_error("Script service not initialized");
|
||||
}
|
||||
|
||||
return engine_->LoadSceneObjects();
|
||||
}
|
||||
|
||||
std::array<float, 16> LuaScriptService::ComputeModelMatrix(int functionRef, float time) {
|
||||
if (!engine_) {
|
||||
throw std::runtime_error("Script service not initialized");
|
||||
}
|
||||
|
||||
return engine_->ComputeModelMatrix(functionRef, time);
|
||||
}
|
||||
|
||||
std::array<float, 16> LuaScriptService::GetViewProjectionMatrix(float aspect) {
|
||||
if (!engine_) {
|
||||
throw std::runtime_error("Script service not initialized");
|
||||
}
|
||||
|
||||
return engine_->GetViewProjectionMatrix(aspect);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, script::ShaderManager::ShaderPaths> LuaScriptService::LoadShaderPathsMap() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!engine_) {
|
||||
throw std::runtime_error("Script service not initialized");
|
||||
}
|
||||
|
||||
return engine_->LoadShaderPathsMap();
|
||||
}
|
||||
|
||||
std::vector<script::GuiCommand> LuaScriptService::LoadGuiCommands() {
|
||||
if (!engine_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return engine_->LoadGuiCommands();
|
||||
}
|
||||
|
||||
void LuaScriptService::UpdateGuiInput(const script::GuiInputSnapshot& input) {
|
||||
if (!engine_) {
|
||||
return;
|
||||
}
|
||||
|
||||
engine_->UpdateGuiInput(input);
|
||||
}
|
||||
|
||||
bool LuaScriptService::HasGuiCommands() const {
|
||||
if (!engine_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return engine_->HasGuiCommands();
|
||||
}
|
||||
|
||||
script::PhysicsBridge& LuaScriptService::GetPhysicsBridge() {
|
||||
if (!engine_) {
|
||||
throw std::runtime_error("Script service not initialized");
|
||||
}
|
||||
|
||||
return engine_->GetPhysicsBridge();
|
||||
}
|
||||
|
||||
void LuaScriptService::SetAudioPlayer(app::AudioPlayer* audioPlayer) {
|
||||
if (!engine_) {
|
||||
return;
|
||||
}
|
||||
|
||||
engine_->SetAudioPlayer(audioPlayer);
|
||||
}
|
||||
|
||||
std::filesystem::path LuaScriptService::GetScriptDirectory() const {
|
||||
if (!engine_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return engine_->GetScriptDirectory();
|
||||
}
|
||||
|
||||
std::string LuaScriptService::GetLuaError() {
|
||||
if (!engine_) {
|
||||
return "Script service not initialized";
|
||||
}
|
||||
|
||||
return engine_->GetLuaError();
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
53
src/services/impl/lua_script_service.hpp
Normal file
53
src/services/impl/lua_script_service.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_script_service.hpp"
|
||||
#include "../../script/script_engine.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
/**
|
||||
* @brief Lua script service implementation.
|
||||
*
|
||||
* Small wrapper service (~100 lines) around ScriptEngine.
|
||||
* Provides Lua script execution and integration with game systems.
|
||||
*/
|
||||
class LuaScriptService : public IScriptService,
|
||||
public di::IInitializable,
|
||||
public di::IShutdownable {
|
||||
public:
|
||||
explicit LuaScriptService(const std::filesystem::path& scriptPath, bool debugEnabled = false);
|
||||
~LuaScriptService() override;
|
||||
|
||||
// Lifecycle
|
||||
void Initialize() override;
|
||||
void Shutdown() noexcept override;
|
||||
|
||||
// IScriptService interface
|
||||
std::vector<script::SceneManager::SceneObject> LoadSceneObjects() override;
|
||||
std::array<float, 16> ComputeModelMatrix(int functionRef, float time) override;
|
||||
std::array<float, 16> GetViewProjectionMatrix(float aspect) override;
|
||||
|
||||
std::unordered_map<std::string, script::ShaderManager::ShaderPaths> LoadShaderPathsMap() override;
|
||||
|
||||
std::vector<script::GuiCommand> LoadGuiCommands() override;
|
||||
void UpdateGuiInput(const script::GuiInputSnapshot& input) override;
|
||||
bool HasGuiCommands() const override;
|
||||
|
||||
script::PhysicsBridge& GetPhysicsBridge() override;
|
||||
|
||||
void SetAudioPlayer(app::AudioPlayer* audioPlayer) override;
|
||||
|
||||
std::filesystem::path GetScriptDirectory() const override;
|
||||
std::string GetLuaError() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<script::ScriptEngine> engine_;
|
||||
std::filesystem::path scriptPath_;
|
||||
bool debugEnabled_ = false;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
102
src/services/impl/sdl_audio_service.cpp
Normal file
102
src/services/impl/sdl_audio_service.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "sdl_audio_service.hpp"
|
||||
#include "../../logging/logger.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
SdlAudioService::SdlAudioService() = default;
|
||||
|
||||
SdlAudioService::~SdlAudioService() {
|
||||
if (initialized_) {
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void SdlAudioService::Initialize() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
audioPlayer_ = std::make_unique<app::AudioPlayer>();
|
||||
initialized_ = true;
|
||||
|
||||
logging::Logger::GetInstance().Info("Audio service initialized");
|
||||
}
|
||||
|
||||
void SdlAudioService::Shutdown() noexcept {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
audioPlayer_.reset();
|
||||
initialized_ = false;
|
||||
|
||||
logging::Logger::GetInstance().Info("Audio service shutdown");
|
||||
}
|
||||
|
||||
void SdlAudioService::PlayBackground(const std::filesystem::path& path, bool loop) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!audioPlayer_) {
|
||||
throw std::runtime_error("Audio service not initialized");
|
||||
}
|
||||
|
||||
audioPlayer_->PlayBackground(path, loop);
|
||||
}
|
||||
|
||||
void SdlAudioService::PlayEffect(const std::filesystem::path& path, bool loop) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!audioPlayer_) {
|
||||
throw std::runtime_error("Audio service not initialized");
|
||||
}
|
||||
|
||||
audioPlayer_->PlayEffect(path, loop);
|
||||
}
|
||||
|
||||
void SdlAudioService::StopBackground() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!audioPlayer_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// AudioPlayer doesn't have StopBackground(), so recreate to stop
|
||||
auto oldPlayer = std::move(audioPlayer_);
|
||||
oldPlayer.reset();
|
||||
audioPlayer_ = std::make_unique<app::AudioPlayer>();
|
||||
}
|
||||
|
||||
void SdlAudioService::StopAll() {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!audioPlayer_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Recreate player to stop all audio
|
||||
audioPlayer_.reset();
|
||||
audioPlayer_ = std::make_unique<app::AudioPlayer>();
|
||||
}
|
||||
|
||||
void SdlAudioService::SetVolume(float volume) {
|
||||
volume_ = std::clamp(volume, 0.0f, 1.0f);
|
||||
// Note: AudioPlayer doesn't expose volume control,
|
||||
// this would need to be added to AudioPlayer implementation
|
||||
}
|
||||
|
||||
float SdlAudioService::GetVolume() const {
|
||||
return volume_;
|
||||
}
|
||||
|
||||
bool SdlAudioService::IsBackgroundPlaying() const {
|
||||
// AudioPlayer doesn't expose this state,
|
||||
// would need to be added to AudioPlayer implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
42
src/services/impl/sdl_audio_service.hpp
Normal file
42
src/services/impl/sdl_audio_service.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_audio_service.hpp"
|
||||
#include "../../app/audio_player.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
/**
|
||||
* @brief SDL audio service implementation.
|
||||
*
|
||||
* Small wrapper service (~80 lines) around AudioPlayer.
|
||||
* Provides thread-safe audio playback for background music and sound effects.
|
||||
*/
|
||||
class SdlAudioService : public IAudioService,
|
||||
public di::IInitializable,
|
||||
public di::IShutdownable {
|
||||
public:
|
||||
SdlAudioService();
|
||||
~SdlAudioService() override;
|
||||
|
||||
// IAudioService interface
|
||||
void Initialize() override;
|
||||
void Shutdown() noexcept override;
|
||||
|
||||
void PlayBackground(const std::filesystem::path& path, bool loop = true) override;
|
||||
void PlayEffect(const std::filesystem::path& path, bool loop = false) override;
|
||||
void StopBackground() override;
|
||||
void StopAll() override;
|
||||
|
||||
void SetVolume(float volume) override;
|
||||
float GetVolume() const override;
|
||||
bool IsBackgroundPlaying() const override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<app::AudioPlayer> audioPlayer_;
|
||||
float volume_ = 1.0f;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
75
src/services/impl/vulkan_gui_service.cpp
Normal file
75
src/services/impl/vulkan_gui_service.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "vulkan_gui_service.hpp"
|
||||
#include "../../logging/logger.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
VulkanGuiService::~VulkanGuiService() {
|
||||
if (initialized_) {
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanGuiService::Initialize(VkDevice device,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
VkFormat format,
|
||||
const std::filesystem::path& resourcePath) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer_ = std::make_unique<gui::GuiRenderer>(device, physicalDevice, format, resourcePath);
|
||||
initialized_ = true;
|
||||
|
||||
logging::Logger::GetInstance().Info("GUI service initialized");
|
||||
}
|
||||
|
||||
void VulkanGuiService::PrepareFrame(const std::vector<GuiCommand>& commands,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!renderer_) {
|
||||
throw std::runtime_error("GUI service not initialized");
|
||||
}
|
||||
|
||||
// GuiRenderer doesn't have a PrepareFrame method in the current implementation
|
||||
// Commands would be processed during RenderToSwapchain
|
||||
}
|
||||
|
||||
void VulkanGuiService::RenderToSwapchain(VkCommandBuffer commandBuffer, VkImage image) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!renderer_) {
|
||||
throw std::runtime_error("GUI service not initialized");
|
||||
}
|
||||
|
||||
renderer_->BlitToSwapchain(commandBuffer, image);
|
||||
}
|
||||
|
||||
void VulkanGuiService::Resize(uint32_t width, uint32_t height, VkFormat format) {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!renderer_) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer_->Resize(width, height, format);
|
||||
}
|
||||
|
||||
void VulkanGuiService::Shutdown() noexcept {
|
||||
logging::TraceGuard trace;
|
||||
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer_.reset();
|
||||
initialized_ = false;
|
||||
|
||||
logging::Logger::GetInstance().Info("GUI service shutdown");
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
43
src/services/impl/vulkan_gui_service.hpp
Normal file
43
src/services/impl/vulkan_gui_service.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_gui_service.hpp"
|
||||
#include "../../gui/gui_renderer.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
/**
|
||||
* @brief Vulkan GUI service implementation.
|
||||
*
|
||||
* Small wrapper service (~60 lines) around GuiRenderer.
|
||||
* Provides 2D GUI overlay rendering for SVG, text, and shapes.
|
||||
*/
|
||||
class VulkanGuiService : public IGuiService,
|
||||
public di::IShutdownable {
|
||||
public:
|
||||
VulkanGuiService() = default;
|
||||
~VulkanGuiService() override;
|
||||
|
||||
// IGuiService interface
|
||||
void Initialize(VkDevice device,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
VkFormat format,
|
||||
const std::filesystem::path& resourcePath) override;
|
||||
|
||||
void PrepareFrame(const std::vector<GuiCommand>& commands,
|
||||
uint32_t width,
|
||||
uint32_t height) override;
|
||||
|
||||
void RenderToSwapchain(VkCommandBuffer commandBuffer, VkImage image) override;
|
||||
|
||||
void Resize(uint32_t width, uint32_t height, VkFormat format) override;
|
||||
|
||||
void Shutdown() noexcept override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<gui::GuiRenderer> renderer_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -1,126 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../core/vertex.hpp"
|
||||
#include "i_graphics_service.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include "../../script/scene_manager.hpp"
|
||||
#include "../../script/shader_manager.hpp"
|
||||
#include "../../script/gui_types.hpp"
|
||||
#include "../../script/physics_bridge.hpp"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::app {
|
||||
class AudioPlayer;
|
||||
}
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
|
||||
/**
|
||||
* @brief Scene object data structure.
|
||||
*/
|
||||
struct SceneObject {
|
||||
std::string id;
|
||||
std::vector<core::Vertex> vertices;
|
||||
std::vector<uint16_t> indices;
|
||||
std::string shaderKey;
|
||||
int modelMatrixFuncRef; // Lua function reference
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief GUI input snapshot for Lua.
|
||||
*/
|
||||
struct GuiInputSnapshot {
|
||||
float mouseX;
|
||||
float mouseY;
|
||||
float mouseWheelDelta;
|
||||
bool mouseLeftPressed;
|
||||
bool mouseRightPressed;
|
||||
std::string textInput;
|
||||
};
|
||||
|
||||
// Forward declare GUI types (defined in script/gui_types.hpp)
|
||||
struct GuiCommand;
|
||||
|
||||
/**
|
||||
* @brief Script service interface (Lua integration).
|
||||
* @brief Script service interface.
|
||||
*
|
||||
* Provides a clean API for Lua script execution and data exchange.
|
||||
* Wraps the ScriptEngine and its internal managers (SceneManager,
|
||||
* ShaderManager, GuiManager, AudioManager).
|
||||
* Provides Lua script execution and integration with scene, shaders, GUI, physics, and audio.
|
||||
*/
|
||||
class IScriptService {
|
||||
public:
|
||||
virtual ~IScriptService() = default;
|
||||
|
||||
/**
|
||||
* @brief Load and execute a Lua script.
|
||||
*
|
||||
* @param path Path to the Lua script file
|
||||
* @param debug Whether to enable Lua debug mode
|
||||
* @throws std::runtime_error if script loading fails
|
||||
*/
|
||||
virtual void LoadScript(const std::filesystem::path& path, bool debug) = 0;
|
||||
|
||||
/**
|
||||
* @brief Load scene objects from Lua.
|
||||
*
|
||||
* Calls the Lua function that generates the scene graph.
|
||||
*
|
||||
* @return Vector of scene objects with geometry and metadata
|
||||
*/
|
||||
virtual std::vector<SceneObject> LoadSceneObjects() = 0;
|
||||
|
||||
/**
|
||||
* @brief Compute model matrix for an object using Lua function.
|
||||
*
|
||||
* @param funcRef Lua function reference (from SceneObject)
|
||||
* @param time Current time in seconds
|
||||
* @return 4x4 model transformation matrix (column-major)
|
||||
*/
|
||||
virtual std::array<float, 16> ComputeModelMatrix(int funcRef, float time) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get view-projection matrix from Lua.
|
||||
*
|
||||
* @param aspect Window aspect ratio (width/height)
|
||||
* @return 4x4 view-projection matrix (column-major)
|
||||
*/
|
||||
// Scene management
|
||||
virtual std::vector<script::SceneManager::SceneObject> LoadSceneObjects() = 0;
|
||||
virtual std::array<float, 16> ComputeModelMatrix(int functionRef, float time) = 0;
|
||||
virtual std::array<float, 16> GetViewProjectionMatrix(float aspect) = 0;
|
||||
|
||||
/**
|
||||
* @brief Load shader paths from Lua configuration.
|
||||
*
|
||||
* @return Map of shader key to shader file paths
|
||||
*/
|
||||
virtual std::unordered_map<std::string, ShaderPaths> LoadShaderPaths() = 0;
|
||||
// Shader management
|
||||
virtual std::unordered_map<std::string, script::ShaderManager::ShaderPaths> LoadShaderPathsMap() = 0;
|
||||
|
||||
/**
|
||||
* @brief Update GUI input state in Lua.
|
||||
*
|
||||
* Sends current input state to Lua for GUI processing.
|
||||
*
|
||||
* @param input Input snapshot for this frame
|
||||
*/
|
||||
virtual void UpdateGuiInput(const GuiInputSnapshot& input) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get GUI rendering commands from Lua.
|
||||
*
|
||||
* Retrieves the list of GUI commands generated by Lua scripts.
|
||||
*
|
||||
* @return Vector of GUI commands to render
|
||||
*/
|
||||
virtual std::vector<GuiCommand> GetGuiCommands() = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if there are pending GUI commands.
|
||||
*
|
||||
* @return true if GUI commands are available, false otherwise
|
||||
*/
|
||||
// GUI management
|
||||
virtual std::vector<script::GuiCommand> LoadGuiCommands() = 0;
|
||||
virtual void UpdateGuiInput(const script::GuiInputSnapshot& input) = 0;
|
||||
virtual bool HasGuiCommands() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Update physics simulation (calls Lua if needed).
|
||||
*
|
||||
* @param deltaTime Time since last update in seconds
|
||||
*/
|
||||
virtual void UpdatePhysics(float deltaTime) = 0;
|
||||
// Physics bridge access
|
||||
virtual script::PhysicsBridge& GetPhysicsBridge() = 0;
|
||||
|
||||
// Audio integration
|
||||
virtual void SetAudioPlayer(app::AudioPlayer* audioPlayer) = 0;
|
||||
|
||||
// Utility
|
||||
virtual std::filesystem::path GetScriptDirectory() const = 0;
|
||||
virtual std::string GetLuaError() = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
|
||||
Reference in New Issue
Block a user