From 0425425ec72879ac78f5f3d1abc20d8c93a43a2f Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Mon, 16 Feb 2026 23:14:12 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20graphics=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84=E5=B9=B6?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E9=85=8D=E7=BD=AE=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重组 graphics 目录,按功能分为 core/camera/shader/texture/memory 子目录 - 移除所有模块级 *_config.h 配置文件,改用模块内部的 Cfg 结构体 - 移除 config_loader 和 debug_config 相关文件 - 简化模块系统,使用 Module 基类替代复杂的 IModuleConfig/IModuleInitializer - 添加 SDL_GetBasePath() 支持跨平台 shader 路径解析 - 修复日志宏不支持 {} 格式化语法的问题 - 更新文档反映新的目录结构 --- Extra2D/include/extra2d/app/application.h | 210 ++----- Extra2D/include/extra2d/audio/audio_config.h | 44 -- .../include/extra2d/config/config_loader.h | 200 ------ .../include/extra2d/config/config_manager.h | 295 --------- .../include/extra2d/config/config_module.h | 70 --- .../include/extra2d/config/module_config.h | 103 ---- .../extra2d/config/module_initializer.h | 63 -- .../include/extra2d/config/module_registry.h | 156 ----- Extra2D/include/extra2d/core/module.h | 76 +++ Extra2D/include/extra2d/core/registry.h | 116 ++++ Extra2D/include/extra2d/debug/debug_config.h | 53 -- Extra2D/include/extra2d/extra2d.h | 32 +- .../extra2d/graphics/{ => camera}/camera.h | 0 .../graphics/{ => camera}/viewport_adapter.h | 0 .../graphics/{ => core}/render_backend.h | 0 .../graphics/{ => core}/render_command.h | 2 +- .../extra2d/graphics/core/render_module.h | 72 +++ .../graphics/{ => core}/render_target.h | 2 +- .../graphics/{ => memory}/gpu_context.h | 0 .../graphics/{ => memory}/vram_manager.h | 0 .../extra2d/graphics/opengl/gl_font_atlas.h | 4 +- .../extra2d/graphics/opengl/gl_renderer.h | 4 +- .../extra2d/graphics/opengl/gl_shader.h | 2 +- .../extra2d/graphics/opengl/gl_sprite_batch.h | 2 +- .../extra2d/graphics/opengl/gl_texture.h | 4 +- .../include/extra2d/graphics/render_config.h | 51 -- .../include/extra2d/graphics/render_module.h | 66 -- .../graphics/{ => shader}/shader_cache.h | 0 .../{ => shader}/shader_hot_reloader.h | 0 .../graphics/{ => shader}/shader_interface.h | 0 .../graphics/{ => shader}/shader_loader.h | 0 .../graphics/{ => shader}/shader_manager.h | 8 +- .../graphics/{ => shader}/shader_preset.h | 2 +- .../graphics/{ => texture}/alpha_mask.h | 0 .../extra2d/graphics/{ => texture}/font.h | 0 .../extra2d/graphics/{ => texture}/texture.h | 0 .../graphics/{ => texture}/texture_atlas.h | 2 +- .../graphics/{ => texture}/texture_pool.h | 2 +- Extra2D/include/extra2d/input/input_config.h | 37 -- .../{platform_module.h => backend_factory.h} | 10 - .../include/extra2d/platform/input_module.h | 132 ++-- .../extra2d/platform/platform_init_module.h | 72 --- .../include/extra2d/platform/window_module.h | 208 ++----- .../extra2d/resource/resource_config.h | 52 -- Extra2D/include/extra2d/scene/node.h | 2 +- Extra2D/include/extra2d/scene/scene.h | 2 +- Extra2D/include/extra2d/scene/sprite.h | 2 +- .../extra2d/scene/transition_box_scene.h | 1 + .../extra2d/scene/transition_fade_scene.h | 6 + .../extra2d/scene/transition_flip_scene.h | 1 + .../extra2d/scene/transition_scale_scene.h | 1 + .../include/extra2d/scene/transition_scene.h | 21 + .../extra2d/scene/transition_slide_scene.h | 1 + .../include/extra2d/services/camera_service.h | 4 +- .../include/extra2d/services/logger_service.h | 228 +++++++ Extra2D/include/extra2d/utils/logger.h | 205 +------ Extra2D/include/extra2d/utils/logger_module.h | 66 -- Extra2D/src/app/application.cpp | 569 +++++++----------- Extra2D/src/config/config_loader_ini.cpp | 341 ----------- Extra2D/src/config/config_loader_json.cpp | 188 ------ Extra2D/src/config/config_manager.cpp | 385 ------------ Extra2D/src/config/config_module.cpp | 114 ---- Extra2D/src/config/module_registry.cpp | 211 ------- Extra2D/src/core/registry.cpp | 96 +++ Extra2D/src/debug/debug_config.cpp | 23 - Extra2D/src/graphics/{ => camera}/camera.cpp | 4 +- .../{ => camera}/viewport_adapter.cpp | 2 +- .../graphics/{ => core}/render_backend.cpp | 2 +- .../graphics/{ => core}/render_command.cpp | 2 +- Extra2D/src/graphics/core/render_module.cpp | 78 +++ .../src/graphics/{ => core}/render_target.cpp | 2 +- .../src/graphics/{ => memory}/gpu_context.cpp | 2 +- .../graphics/{ => memory}/vram_manager.cpp | 2 +- Extra2D/src/graphics/opengl/gl_renderer.cpp | 8 +- Extra2D/src/graphics/opengl/gl_texture.cpp | 4 +- Extra2D/src/graphics/render_module.cpp | 214 ------- .../graphics/{ => shader}/shader_cache.cpp | 2 +- .../{ => shader}/shader_hot_reloader.cpp | 2 +- .../graphics/{ => shader}/shader_loader.cpp | 2 +- .../graphics/{ => shader}/shader_manager.cpp | 2 +- .../graphics/{ => shader}/shader_preset.cpp | 4 +- .../src/graphics/{ => texture}/alpha_mask.cpp | 2 +- .../graphics/{ => texture}/texture_atlas.cpp | 2 +- .../graphics/{ => texture}/texture_pool.cpp | 4 +- ...latform_module.cpp => backend_factory.cpp} | 2 +- .../platform/backends/sdl2/sdl2_backend.cpp | 2 +- Extra2D/src/platform/input_module.cpp | 196 +----- Extra2D/src/platform/platform_init_module.cpp | 168 ------ Extra2D/src/platform/window_module.cpp | 264 ++------ Extra2D/src/resource/resource_config.cpp | 23 - Extra2D/src/scene/node.cpp | 2 +- Extra2D/src/scene/scene.cpp | 4 +- Extra2D/src/scene/scene_manager.cpp | 18 +- Extra2D/src/scene/shape_node.cpp | 4 +- Extra2D/src/scene/sprite.cpp | 6 +- Extra2D/src/scene/transition_box_scene.cpp | 22 +- Extra2D/src/scene/transition_fade_scene.cpp | 32 +- Extra2D/src/scene/transition_flip_scene.cpp | 18 +- Extra2D/src/scene/transition_scale_scene.cpp | 18 +- Extra2D/src/scene/transition_scene.cpp | 47 +- Extra2D/src/scene/transition_slide_scene.cpp | 18 +- Extra2D/src/services/logger_service.cpp | 171 ++++++ Extra2D/src/utils/logger.cpp | 177 ------ Extra2D/src/utils/logger_module.cpp | 114 ---- README.md | 52 ++ docs/module_system.md | 88 ++- examples/basic/main.cpp | 69 ++- examples/hello_module/hello_module.cpp | 171 +----- examples/hello_module/hello_module.h | 146 +---- examples/hello_module/main.cpp | 77 +-- 110 files changed, 1692 insertions(+), 5176 deletions(-) delete mode 100644 Extra2D/include/extra2d/audio/audio_config.h delete mode 100644 Extra2D/include/extra2d/config/config_loader.h delete mode 100644 Extra2D/include/extra2d/config/config_manager.h delete mode 100644 Extra2D/include/extra2d/config/config_module.h delete mode 100644 Extra2D/include/extra2d/config/module_config.h delete mode 100644 Extra2D/include/extra2d/config/module_initializer.h delete mode 100644 Extra2D/include/extra2d/config/module_registry.h create mode 100644 Extra2D/include/extra2d/core/module.h create mode 100644 Extra2D/include/extra2d/core/registry.h delete mode 100644 Extra2D/include/extra2d/debug/debug_config.h rename Extra2D/include/extra2d/graphics/{ => camera}/camera.h (100%) rename Extra2D/include/extra2d/graphics/{ => camera}/viewport_adapter.h (100%) rename Extra2D/include/extra2d/graphics/{ => core}/render_backend.h (100%) rename Extra2D/include/extra2d/graphics/{ => core}/render_command.h (99%) create mode 100644 Extra2D/include/extra2d/graphics/core/render_module.h rename Extra2D/include/extra2d/graphics/{ => core}/render_target.h (99%) rename Extra2D/include/extra2d/graphics/{ => memory}/gpu_context.h (100%) rename Extra2D/include/extra2d/graphics/{ => memory}/vram_manager.h (100%) delete mode 100644 Extra2D/include/extra2d/graphics/render_config.h delete mode 100644 Extra2D/include/extra2d/graphics/render_module.h rename Extra2D/include/extra2d/graphics/{ => shader}/shader_cache.h (100%) rename Extra2D/include/extra2d/graphics/{ => shader}/shader_hot_reloader.h (100%) rename Extra2D/include/extra2d/graphics/{ => shader}/shader_interface.h (100%) rename Extra2D/include/extra2d/graphics/{ => shader}/shader_loader.h (100%) rename Extra2D/include/extra2d/graphics/{ => shader}/shader_manager.h (97%) rename Extra2D/include/extra2d/graphics/{ => shader}/shader_preset.h (98%) rename Extra2D/include/extra2d/graphics/{ => texture}/alpha_mask.h (100%) rename Extra2D/include/extra2d/graphics/{ => texture}/font.h (100%) rename Extra2D/include/extra2d/graphics/{ => texture}/texture.h (100%) rename Extra2D/include/extra2d/graphics/{ => texture}/texture_atlas.h (99%) rename Extra2D/include/extra2d/graphics/{ => texture}/texture_pool.h (99%) delete mode 100644 Extra2D/include/extra2d/input/input_config.h rename Extra2D/include/extra2d/platform/{platform_module.h => backend_factory.h} (92%) delete mode 100644 Extra2D/include/extra2d/platform/platform_init_module.h delete mode 100644 Extra2D/include/extra2d/resource/resource_config.h create mode 100644 Extra2D/include/extra2d/services/logger_service.h delete mode 100644 Extra2D/include/extra2d/utils/logger_module.h delete mode 100644 Extra2D/src/config/config_loader_ini.cpp delete mode 100644 Extra2D/src/config/config_loader_json.cpp delete mode 100644 Extra2D/src/config/config_manager.cpp delete mode 100644 Extra2D/src/config/config_module.cpp delete mode 100644 Extra2D/src/config/module_registry.cpp create mode 100644 Extra2D/src/core/registry.cpp delete mode 100644 Extra2D/src/debug/debug_config.cpp rename Extra2D/src/graphics/{ => camera}/camera.cpp (98%) rename Extra2D/src/graphics/{ => camera}/viewport_adapter.cpp (99%) rename Extra2D/src/graphics/{ => core}/render_backend.cpp (91%) rename Extra2D/src/graphics/{ => core}/render_command.cpp (99%) create mode 100644 Extra2D/src/graphics/core/render_module.cpp rename Extra2D/src/graphics/{ => core}/render_target.cpp (99%) rename Extra2D/src/graphics/{ => memory}/gpu_context.cpp (95%) rename Extra2D/src/graphics/{ => memory}/vram_manager.cpp (98%) delete mode 100644 Extra2D/src/graphics/render_module.cpp rename Extra2D/src/graphics/{ => shader}/shader_cache.cpp (99%) rename Extra2D/src/graphics/{ => shader}/shader_hot_reloader.cpp (98%) rename Extra2D/src/graphics/{ => shader}/shader_loader.cpp (99%) rename Extra2D/src/graphics/{ => shader}/shader_manager.cpp (99%) rename Extra2D/src/graphics/{ => shader}/shader_preset.cpp (98%) rename Extra2D/src/graphics/{ => texture}/alpha_mask.cpp (98%) rename Extra2D/src/graphics/{ => texture}/texture_atlas.cpp (99%) rename Extra2D/src/graphics/{ => texture}/texture_pool.cpp (99%) rename Extra2D/src/platform/{platform_module.cpp => backend_factory.cpp} (96%) delete mode 100644 Extra2D/src/platform/platform_init_module.cpp delete mode 100644 Extra2D/src/resource/resource_config.cpp create mode 100644 Extra2D/src/services/logger_service.cpp delete mode 100644 Extra2D/src/utils/logger.cpp delete mode 100644 Extra2D/src/utils/logger_module.cpp diff --git a/Extra2D/include/extra2d/app/application.h b/Extra2D/include/extra2d/app/application.h index df343e9..2e11d4d 100644 --- a/Extra2D/include/extra2d/app/application.h +++ b/Extra2D/include/extra2d/app/application.h @@ -1,231 +1,143 @@ #pragma once #include +#include +#include #include #include -#include -#include -#include #include namespace extra2d { +class IWindow; class IInput; class RenderBackend; +class WindowModule; +class RenderModule; +class InputModule; /** * @brief 应用程序类 - * 使用服务定位器模式管理模块依赖,支持依赖注入和测试Mock */ class Application { public: - /** - * @brief 获取单例实例 - * @return 应用程序实例引用 - */ static Application& get(); - + Application(const Application&) = delete; Application& operator=(const Application&) = delete; - + /** - * @brief 使用默认配置初始化 + * @brief 注册模块 + * @tparam T 模块类型 + * @tparam Args 构造函数参数 + * @return 模块指针 + */ + template + T* use(Args&&... args) { + return Registry::instance().use(std::forward(args)...); + } + + /** + * @brief 获取模块 + * @tparam T 模块类型 + * @return 模块指针 + */ + template + T* get() const { + return Registry::instance().get(); + } + + /** + * @brief 初始化 * @return 初始化成功返回 true */ bool init(); - + /** - * @brief 使用指定配置初始化 + * @brief 初始化(带配置) * @param config 应用配置 * @return 初始化成功返回 true */ bool init(const AppConfig& config); - + /** - * @brief 使用配置文件初始化 - * @param configPath 配置文件路径 - * @return 初始化成功返回 true - */ - bool init(const std::string& configPath); - - /** - * @brief 关闭应用程序 + * @brief 关闭 */ void shutdown(); - + /** * @brief 运行主循环 */ void run(); - + /** * @brief 请求退出 */ void quit(); - + /** - * @brief 暂停应用程序 + * @brief 暂停 */ void pause(); - + /** - * @brief 恢复应用程序 + * @brief 恢复 */ void resume(); - - /** - * @brief 检查是否暂停 - * @return 暂停状态返回 true - */ + bool isPaused() const { return paused_; } - - /** - * @brief 检查是否运行中 - * @return 运行中返回 true - */ bool isRunning() const { return running_; } - + /** * @brief 获取窗口 - * @return 窗口引用 + * @return 窗口指针 */ - IWindow& window() { return *window_; } - + IWindow* window(); + /** * @brief 获取渲染器 - * @return 渲染器引用 + * @return 渲染器指针 */ - RenderBackend& renderer(); - + RenderBackend* renderer(); + /** - * @brief 获取输入接口 - * @return 输入接口引用 + * @brief 获取输入 + * @return 输入指针 */ - IInput& input(); - - /** - * @brief 获取场景服务 - * @return 场景服务共享指针 - */ - SharedPtr scenes(); - - /** - * @brief 获取计时器服务 - * @return 计时器服务共享指针 - */ - SharedPtr timers(); - - /** - * @brief 获取事件服务 - * @return 事件服务共享指针 - */ - SharedPtr events(); - - /** - * @brief 获取相机服务 - * @return 相机服务共享指针 - */ - SharedPtr camera(); - + IInput* input(); + /** * @brief 进入场景 * @param scene 场景指针 */ void enterScene(Ptr scene); - - /** - * @brief 获取帧间隔时间 - * @return 帧间隔时间(秒) - */ + float deltaTime() const { return deltaTime_; } - - /** - * @brief 获取总运行时间 - * @return 总运行时间(秒) - */ float totalTime() const { return totalTime_; } - - /** - * @brief 获取当前帧率 - * @return 帧率 - */ int fps() const { return currentFps_; } - /** - * @brief 获取配置管理器 - * @return 配置管理器引用 - */ - ConfigManager& config(); - - /** - * @brief 获取应用配置 - * @return 应用配置常量引用 - */ - const AppConfig& getConfig() const; - - /** - * @brief 注册自定义服务 - * @tparam T 服务接口类型 - * @param service 服务实例 - */ - template - void registerService(SharedPtr service) { - ServiceLocator::instance().registerService(service); - } - - /** - * @brief 获取服务 - * @tparam T 服务接口类型 - * @return 服务共享指针 - */ - template - SharedPtr getService() { - return ServiceLocator::instance().getService(); - } - private: - Application() = default; + Application(); ~Application(); - - /** - * @brief 初始化模块 - * @return 初始化成功返回 true - */ - bool initModules(); - - /** - * @brief 注册核心服务 - */ - void registerCoreServices(); - - /** - * @brief 主循环 - */ + void mainLoop(); - - /** - * @brief 更新 - */ void update(); - - /** - * @brief 渲染 - */ void render(); - - IWindow* window_ = nullptr; - + void registerCoreServices(); + bool initialized_ = false; bool running_ = false; bool paused_ = false; bool shouldQuit_ = false; - + float deltaTime_ = 0.0f; float totalTime_ = 0.0f; double lastFrameTime_ = 0.0; int frameCount_ = 0; float fpsTimer_ = 0.0f; int currentFps_ = 0; + + AppConfig appConfig_; }; -} +} // namespace extra2d diff --git a/Extra2D/include/extra2d/audio/audio_config.h b/Extra2D/include/extra2d/audio/audio_config.h deleted file mode 100644 index 719e97f..0000000 --- a/Extra2D/include/extra2d/audio/audio_config.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -namespace extra2d { - -/** - * @file audio_config.h - * @brief 音频模块配置 - * - * 定义音频相关的配置数据结构,由 AudioModule 管理。 - */ - -/** - * @brief 音频配置数据结构 - */ -struct AudioConfigData { - bool enabled = true; - int masterVolume = 100; - int musicVolume = 100; - int sfxVolume = 100; - int voiceVolume = 100; - int ambientVolume = 100; - int frequency = 44100; - int channels = 2; - int chunkSize = 2048; - int maxChannels = 16; - bool spatialAudio = false; - float listenerPosition[3] = {0.0f, 0.0f, 0.0f}; - - /** - * @brief 验证音量值是否有效 - * @param volume 要验证的音量值 - * @return 如果音量在0-100范围内返回 true - */ - bool isValidVolume(int volume) const { return volume >= 0 && volume <= 100; } - - /** - * @brief 将音量值转换为浮点数 - * @param volume 音量值(0-100) - * @return 浮点数音量值(0.0-1.0) - */ - float volumeToFloat(int volume) const { return static_cast(volume) / 100.0f; } -}; - -} diff --git a/Extra2D/include/extra2d/config/config_loader.h b/Extra2D/include/extra2d/config/config_loader.h deleted file mode 100644 index 50af30c..0000000 --- a/Extra2D/include/extra2d/config/config_loader.h +++ /dev/null @@ -1,200 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace extra2d { - -/** - * @file config_loader.h - * @brief 配置加载器接口 - * - * 配置加载器只负责加载应用级别的配置(AppConfig)。 - * 模块配置通过 ModuleRegistry 和各模块的 IModuleConfig 接口加载。 - */ - -/** - * @brief 配置加载结果 - */ -struct ConfigLoadResult { - bool success = false; - std::string errorMessage; - int errorLine = -1; - std::string errorField; - - static ConfigLoadResult ok() { return ConfigLoadResult{true, "", -1, ""}; } - static ConfigLoadResult error(const std::string& msg, int line = -1, const std::string& field = "") { - return ConfigLoadResult{false, msg, line, field}; - } - - bool isOk() const { return success; } - bool hasError() const { return !success; } -}; - -/** - * @brief 配置保存结果 - */ -struct ConfigSaveResult { - bool success = false; - std::string errorMessage; - - static ConfigSaveResult ok() { return ConfigSaveResult{true, ""}; } - static ConfigSaveResult error(const std::string& msg) { - return ConfigSaveResult{false, msg}; - } - - bool isOk() const { return success; } - bool hasError() const { return !success; } -}; - -/** - * @brief 配置加载器抽象接口 - */ -class ConfigLoader { -public: - virtual ~ConfigLoader() = default; - - /** - * @brief 从文件加载应用配置 - * @param filepath 配置文件路径 - * @param config 输出的配置对象 - * @return 加载结果 - */ - virtual ConfigLoadResult load(const std::string& filepath, AppConfig& config) = 0; - - /** - * @brief 保存应用配置到文件 - * @param filepath 配置文件路径 - * @param config 要保存的配置对象 - * @return 保存结果 - */ - virtual ConfigSaveResult save(const std::string& filepath, const AppConfig& config) = 0; - - /** - * @brief 从字符串加载配置 - * @param content 配置内容字符串 - * @param config 输出的配置对象 - * @return 加载结果 - */ - virtual ConfigLoadResult loadFromString(const std::string& content, AppConfig& config) = 0; - - /** - * @brief 将配置序列化为字符串 - * @param config 配置对象 - * @return 序列化后的字符串 - */ - virtual std::string saveToString(const AppConfig& config) = 0; - - /** - * @brief 从文件加载完整配置(包括模块配置) - * @param filepath 配置文件路径 - * @return 加载结果 - */ - virtual ConfigLoadResult loadWithModules(const std::string& filepath) = 0; - - /** - * @brief 保存完整配置(包括模块配置)到文件 - * @param filepath 配置文件路径 - * @return 保存结果 - */ - virtual ConfigSaveResult saveWithModules(const std::string& filepath) = 0; - - /** - * @brief 获取支持的文件扩展名 - * @return 文件扩展名(不含点号,如 "json") - */ - virtual const char* extension() const = 0; - - /** - * @brief 检查是否支持指定文件 - * @param filepath 文件路径 - * @return 如果支持返回 true - */ - virtual bool supportsFile(const std::string& filepath) const = 0; - - /** - * @brief 克隆加载器实例 - * @return 新的加载器实例 - */ - virtual UniquePtr clone() const = 0; -}; - -/** - * @brief JSON 配置加载器 - */ -class JsonConfigLoader : public ConfigLoader { -public: - JsonConfigLoader() = default; - ~JsonConfigLoader() override = default; - - ConfigLoadResult load(const std::string& filepath, AppConfig& config) override; - ConfigSaveResult save(const std::string& filepath, const AppConfig& config) override; - ConfigLoadResult loadFromString(const std::string& content, AppConfig& config) override; - std::string saveToString(const AppConfig& config) override; - ConfigLoadResult loadWithModules(const std::string& filepath) override; - ConfigSaveResult saveWithModules(const std::string& filepath) override; - const char* extension() const override { return "json"; } - bool supportsFile(const std::string& filepath) const override; - UniquePtr clone() const override; -}; - -/** - * @brief INI 配置加载器 - */ -class IniConfigLoader : public ConfigLoader { -public: - IniConfigLoader() = default; - ~IniConfigLoader() override = default; - - ConfigLoadResult load(const std::string& filepath, AppConfig& config) override; - ConfigSaveResult save(const std::string& filepath, const AppConfig& config) override; - ConfigLoadResult loadFromString(const std::string& content, AppConfig& config) override; - std::string saveToString(const AppConfig& config) override; - ConfigLoadResult loadWithModules(const std::string& filepath) override; - ConfigSaveResult saveWithModules(const std::string& filepath) override; - const char* extension() const override { return "ini"; } - bool supportsFile(const std::string& filepath) const override; - UniquePtr clone() const override; - -private: - std::string sectionKey(const std::string& section, const std::string& key) const; - ConfigLoadResult parseInt(const std::string& value, int& result, const std::string& fieldName); - ConfigLoadResult parseFloat(const std::string& value, float& result, const std::string& fieldName); - ConfigLoadResult parseBool(const std::string& value, bool& result, const std::string& fieldName); -}; - -/** - * @brief 配置加载器工厂 - */ -class ConfigLoaderFactory { -public: - /** - * @brief 根据文件扩展名创建加载器 - * @param extension 文件扩展名(不含点号) - * @return 配置加载器实例,如果不支持返回 nullptr - */ - static UniquePtr create(const std::string& extension); - - /** - * @brief 根据文件路径创建加载器 - * @param filepath 文件路径 - * @return 配置加载器实例,如果不支持返回 nullptr - */ - static UniquePtr createForFile(const std::string& filepath); - - /** - * @brief 检查是否支持指定扩展名 - * @param extension 文件扩展名 - * @return 如果支持返回 true - */ - static bool isExtensionSupported(const std::string& extension); - - /** - * @brief 获取所有支持的扩展名 - * @return 支持的扩展名列表 - */ - static std::vector getSupportedExtensions(); -}; - -} diff --git a/Extra2D/include/extra2d/config/config_manager.h b/Extra2D/include/extra2d/config/config_manager.h deleted file mode 100644 index 18da0c2..0000000 --- a/Extra2D/include/extra2d/config/config_manager.h +++ /dev/null @@ -1,295 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace extra2d { - -/** - * @file config_manager.h - * @brief 配置管理器 - * - * 配置管理器只管理应用级别的配置(AppConfig)。 - * 模块配置通过 ModuleRegistry 管理,各模块实现 IModuleConfig 接口。 - */ - -/** - * @brief 配置变更事件 - */ -struct ConfigChangeEvent { - std::string section; - std::string field; - std::string oldValue; - std::string newValue; -}; - -/** - * @brief 配置变更回调类型 - */ -using ConfigChangeCallback = Function; - -/** - * @brief 配置管理器(单例) - */ -class ConfigManager { -public: - /** - * @brief 获取单例实例 - * @return 配置管理器实例引用 - */ - static ConfigManager &instance(); - - /** - * @brief 初始化配置管理器 - * @param configPath 配置文件路径 - * @return 如果初始化成功返回 true - */ - bool initialize(const std::string &configPath = "config.json"); - - /** - * @brief 关闭配置管理器 - */ - void shutdown(); - - /** - * @brief 检查是否已初始化 - * @return 如果已初始化返回 true - */ - bool isInitialized() const; - - /** - * @brief 加载配置文件 - * @param filepath 配置文件路径(可选,默认使用初始化时的路径) - * @return 加载结果 - */ - ConfigLoadResult loadConfig(const std::string &filepath = ""); - - /** - * @brief 保存配置到文件 - * @param filepath 配置文件路径(可选,默认使用初始化时的路径) - * @return 保存结果 - */ - ConfigSaveResult saveConfig(const std::string &filepath = ""); - - /** - * @brief 加载完整配置(包括模块配置) - * @param filepath 配置文件路径 - * @return 加载结果 - */ - ConfigLoadResult loadConfigWithModules(const std::string &filepath = ""); - - /** - * @brief 保存完整配置(包括模块配置) - * @param filepath 配置文件路径 - * @return 保存结果 - */ - ConfigSaveResult saveConfigWithModules(const std::string &filepath = ""); - - /** - * @brief 重新加载配置 - * @return 加载结果 - */ - ConfigLoadResult reload(); - - /** - * @brief 获取应用配置 - * @return 应用配置的常量引用 - */ - const AppConfig &appConfig() const; - - /** - * @brief 获取可修改的应用配置 - * @return 应用配置的引用 - */ - AppConfig &appConfig(); - - /** - * @brief 设置应用配置 - * @param config 新的配置 - */ - void setAppConfig(const AppConfig &config); - - /** - * @brief 获取平台配置 - * @return 平台配置接口指针 - */ - PlatformConfig *platformConfig(); - - /** - * @brief 获取平台配置(常量版本) - * @return 平台配置接口常量指针 - */ - const PlatformConfig *platformConfig() const; - - /** - * @brief 注册配置变更回调 - * @param callback 回调函数 - * @return 回调ID,用于取消注册 - */ - int registerChangeCallback(ConfigChangeCallback callback); - - /** - * @brief 取消注册配置变更回调 - * @param callbackId 回调ID - */ - void unregisterChangeCallback(int callbackId); - - /** - * @brief 清除所有变更回调 - */ - void clearChangeCallbacks(); - - /** - * @brief 设置配置值(字符串) - * @param section 配置节 - * @param key 配置键 - * @param value 配置值 - */ - void setValue(const std::string §ion, const std::string &key, - const std::string &value); - - /** - * @brief 设置配置值(整数) - * @param section 配置节 - * @param key 配置键 - * @param value 配置值 - */ - void setValue(const std::string §ion, const std::string &key, int value); - - /** - * @brief 设置配置值(浮点数) - * @param section 配置节 - * @param key 配置键 - * @param value 配置值 - */ - void setValue(const std::string §ion, const std::string &key, - float value); - - /** - * @brief 设置配置值(布尔值) - * @param section 配置节 - * @param key 配置键 - * @param value 配置值 - */ - void setValue(const std::string §ion, const std::string &key, bool value); - - /** - * @brief 获取配置值(字符串) - * @param section 配置节 - * @param key 配置键 - * @param defaultValue 默认值 - * @return 配置值 - */ - std::string getValue(const std::string §ion, const std::string &key, - const std::string &defaultValue = "") const; - - /** - * @brief 获取配置值(整数) - * @param section 配置节 - * @param key 配置键 - * @param defaultValue 默认值 - * @return 配置值 - */ - int getIntValue(const std::string §ion, const std::string &key, - int defaultValue = 0) const; - - /** - * @brief 获取配置值(浮点数) - * @param section 配置节 - * @param key 配置键 - * @param defaultValue 默认值 - * @return 配置值 - */ - float getFloatValue(const std::string §ion, const std::string &key, - float defaultValue = 0.0f) const; - - /** - * @brief 获取配置值(布尔值) - * @param section 配置节 - * @param key 配置键 - * @param defaultValue 默认值 - * @return 配置值 - */ - bool getBoolValue(const std::string §ion, const std::string &key, - bool defaultValue = false) const; - - /** - * @brief 重置配置到默认值 - */ - void resetToDefaults(); - - /** - * @brief 检查配置是否有未保存的更改 - * @return 如果有未保存的更改返回 true - */ - bool hasUnsavedChanges() const; - - /** - * @brief 标记配置为已修改 - */ - void markModified(); - - /** - * @brief 清除修改标记 - */ - void clearModified(); - - /** - * @brief 获取配置文件路径 - * @return 配置文件路径 - */ - const std::string &configPath() const { return m_configPath; } - - /** - * @brief 设置自动保存 - * @param enabled 是否启用自动保存 - * @param interval 自动保存间隔(秒) - */ - void setAutoSave(bool enabled, float interval = 30.0f); - - /** - * @brief 检查是否启用自动保存 - * @return 如果启用自动保存返回 true - */ - bool isAutoSaveEnabled() const { return m_autoSaveEnabled; } - - /** - * @brief 更新配置管理器(用于自动保存) - * @param deltaTime 帧时间(秒) - */ - void update(float deltaTime); - -private: - ConfigManager(); - ~ConfigManager(); - ConfigManager(const ConfigManager &) = delete; - ConfigManager &operator=(const ConfigManager &) = delete; - - void notifyChangeCallbacks(const ConfigChangeEvent &event); - - AppConfig m_appConfig; - UniquePtr m_platformConfig; - UniquePtr m_loader; - std::string m_configPath; - bool m_initialized = false; - bool m_modified = false; - mutable std::mutex m_mutex; - - std::unordered_map m_changeCallbacks; - int m_nextCallbackId = 1; - - std::unordered_map m_rawValues; - - bool m_autoSaveEnabled = false; - float m_autoSaveInterval = 30.0f; - float m_autoSaveTimer = 0.0f; -}; - -#define CONFIG_MANAGER ConfigManager::instance() - -} diff --git a/Extra2D/include/extra2d/config/config_module.h b/Extra2D/include/extra2d/config/config_module.h deleted file mode 100644 index f370689..0000000 --- a/Extra2D/include/extra2d/config/config_module.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace extra2d { - -class ConfigModuleConfig : public IModuleConfig { -public: - std::string configPath; - AppConfig appConfig; - - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.id = 0; - info.name = "Config"; - info.version = "1.0.0"; - info.priority = ModulePriority::Core; - info.enabled = true; - return info; - } - - std::string getConfigSectionName() const override { - return "config"; - } - - bool validate() const override { - return true; - } - - void resetToDefaults() override { - configPath.clear(); - appConfig = AppConfig{}; - } - - bool loadFromJson(const void* jsonData) override; - bool saveToJson(void* jsonData) const override; -}; - -class ConfigModuleInitializer : public IModuleInitializer { -public: - ConfigModuleInitializer(); - ~ConfigModuleInitializer() override; - - ModuleId getModuleId() const override { return moduleId_; } - ModulePriority getPriority() const override { return ModulePriority::Core; } - std::vector getDependencies() const override { return {}; } - - bool initialize(const IModuleConfig* config) override; - void shutdown() override; - bool isInitialized() const override { return initialized_; } - - void setModuleId(ModuleId id) { moduleId_ = id; } - void setAppConfig(const AppConfig& config) { appConfig_ = config; } - void setConfigPath(const std::string& path) { configPath_ = path; } - -private: - ModuleId moduleId_ = INVALID_MODULE_ID; - bool initialized_ = false; - AppConfig appConfig_; - std::string configPath_; -}; - -ModuleId get_config_module_id(); -void register_config_module(); - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/config/module_config.h b/Extra2D/include/extra2d/config/module_config.h deleted file mode 100644 index d67691a..0000000 --- a/Extra2D/include/extra2d/config/module_config.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace extra2d { - -/** - * @brief 模块标识符类型 - */ -using ModuleId = uint32_t; - -/** - * @brief 无效模块标识符常量 - */ -constexpr ModuleId INVALID_MODULE_ID = 0; - -/** - * @brief 模块优先级枚举 - * 定义模块的初始化顺序,数值越小越先初始化 - */ -enum class ModulePriority : int { - Core = 0, ///< 核心模块(最先初始化) - Platform = 100, ///< 平台相关模块 - Graphics = 200, ///< 图形渲染模块 - Audio = 300, ///< 音频模块 - Input = 400, ///< 输入模块 - Resource = 500, ///< 资源管理模块 - Game = 1000, ///< 游戏逻辑模块 - User = 2000 ///< 用户自定义模块 -}; - -/** - * @brief 模块信息结构体 - * 包含模块的基本信息 - */ -struct ModuleInfo { - ModuleId id = INVALID_MODULE_ID; ///< 模块唯一标识符 - std::string name; ///< 模块名称 - std::string version; ///< 模块版本号 - ModulePriority priority = ModulePriority::User; ///< 模块优先级 - bool enabled = true; ///< 是否启用 -}; - -/** - * @brief 模块配置接口 - * 所有模块配置类必须实现此接口 - */ -class IModuleConfig { -public: - /** - * @brief 虚析构函数 - */ - virtual ~IModuleConfig() = default; - - /** - * @brief 获取模块信息 - * @return 模块信息结构体 - */ - virtual ModuleInfo getModuleInfo() const = 0; - - /** - * @brief 获取配置节名称 - * 用于配置文件中的节名 - * @return 配置节名称字符串 - */ - virtual std::string getConfigSectionName() const = 0; - - /** - * @brief 验证配置有效性 - * @return 如果配置有效返回 true - */ - virtual bool validate() const { return true; } - - /** - * @brief 应用平台约束 - * 根据平台特性调整配置 - * @param platform 目标平台类型 - */ - virtual void applyPlatformConstraints(PlatformType platform) { } - - /** - * @brief 重置为默认配置 - */ - virtual void resetToDefaults() = 0; - - /** - * @brief 从 JSON 数据加载配置 - * @param jsonData JSON 数据指针 - * @return 加载成功返回 true - */ - virtual bool loadFromJson(const void* jsonData) { return true; } - - /** - * @brief 保存配置到 JSON 数据 - * @param jsonData JSON 数据指针 - * @return 保存成功返回 true - */ - virtual bool saveToJson(void* jsonData) const { return true; } -}; - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/config/module_initializer.h b/Extra2D/include/extra2d/config/module_initializer.h deleted file mode 100644 index a4f50c2..0000000 --- a/Extra2D/include/extra2d/config/module_initializer.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace extra2d { - -/** - * @brief 模块初始化器接口 - * 所有模块初始化器必须实现此接口 - */ -class IModuleInitializer { -public: - /** - * @brief 虚析构函数 - */ - virtual ~IModuleInitializer() = default; - - /** - * @brief 获取模块标识符 - * @return 模块唯一标识符 - */ - virtual ModuleId getModuleId() const = 0; - - /** - * @brief 获取模块优先级 - * @return 模块优先级 - */ - virtual ModulePriority getPriority() const = 0; - - /** - * @brief 获取模块依赖列表 - * 返回此模块依赖的其他模块标识符 - * @return 依赖模块标识符列表 - */ - virtual std::vector getDependencies() const { return {}; } - - /** - * @brief 初始化模块 - * @param config 模块配置指针 - * @return 初始化成功返回 true - */ - virtual bool initialize(const IModuleConfig* config) = 0; - - /** - * @brief 关闭模块 - */ - virtual void shutdown() = 0; - - /** - * @brief 检查模块是否已初始化 - * @return 已初始化返回 true - */ - virtual bool isInitialized() const = 0; -}; - -/** - * @brief 模块初始化器工厂函数类型 - */ -using ModuleInitializerFactory = std::function()>; - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/config/module_registry.h b/Extra2D/include/extra2d/config/module_registry.h deleted file mode 100644 index 64d6e32..0000000 --- a/Extra2D/include/extra2d/config/module_registry.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace extra2d { - -/** - * @brief 模块注册表条目结构体 - * 存储模块的配置和初始化器 - */ -struct ModuleEntry { - ModuleId id; ///< 模块标识符 - UniquePtr config; ///< 模块配置 - ModuleInitializerFactory initializerFactory;///< 初始化器工厂函数 - UniquePtr initializer; ///< 初始化器实例 - bool initialized = false; ///< 是否已初始化 -}; - -/** - * @brief 模块注册表类 - * 单例模式,管理所有模块的注册、查询和初始化顺序 - */ -class ModuleRegistry { -public: - /** - * @brief 获取单例实例 - * @return 模块注册表实例引用 - */ - static ModuleRegistry& instance(); - - /** - * @brief 禁止拷贝构造 - */ - ModuleRegistry(const ModuleRegistry&) = delete; - - /** - * @brief 禁止赋值操作 - */ - ModuleRegistry& operator=(const ModuleRegistry&) = delete; - - /** - * @brief 注册模块 - * @param config 模块配置 - * @param initializerFactory 初始化器工厂函数(可选) - * @return 分配的模块标识符 - */ - ModuleId registerModule( - UniquePtr config, - ModuleInitializerFactory initializerFactory = nullptr - ); - - /** - * @brief 注销模块 - * @param id 模块标识符 - * @return 注销成功返回 true - */ - bool unregisterModule(ModuleId id); - - /** - * @brief 获取模块配置 - * @param id 模块标识符 - * @return 模块配置指针,不存在返回 nullptr - */ - IModuleConfig* getModuleConfig(ModuleId id) const; - - /** - * @brief 根据名称获取模块配置 - * @param name 模块名称 - * @return 模块配置指针,不存在返回 nullptr - */ - IModuleConfig* getModuleConfigByName(const std::string& name) const; - - /** - * @brief 获取或创建模块初始化器 - * @param id 模块标识符 - * @return 初始化器指针,不存在返回 nullptr - */ - IModuleInitializer* getInitializer(ModuleId id); - - /** - * @brief 获取所有已注册模块标识符 - * @return 模块标识符列表 - */ - std::vector getAllModules() const; - - /** - * @brief 获取模块初始化顺序 - * 根据优先级和依赖关系计算初始化顺序 - * @return 按初始化顺序排列的模块标识符列表 - */ - std::vector getInitializationOrder() const; - - /** - * @brief 检查模块是否存在 - * @param id 模块标识符 - * @return 存在返回 true - */ - bool hasModule(ModuleId id) const; - - /** - * @brief 清空所有注册的模块 - */ - void clear(); - - /** - * @brief 获取已注册模块数量 - * @return 模块数量 - */ - size_t size() const { return modules_.size(); } - -private: - /** - * @brief 私有构造函数 - */ - ModuleRegistry() = default; - - /** - * @brief 私有析构函数 - */ - ~ModuleRegistry() = default; - - /** - * @brief 生成新的模块标识符 - * @return 新的模块标识符 - */ - ModuleId generateId(); - - std::unordered_map modules_; ///< 模块注册表 - std::unordered_map nameToId_; ///< 名称到标识符映射 - mutable std::mutex mutex_; ///< 线程安全互斥锁 - ModuleId nextId_ = 1; ///< 下一个可用标识符 -}; - -/** - * @brief 模块注册宏 - * 在全局作用域使用此宏注册模块 - * - * @example - * E2D_REGISTER_MODULE(MyModuleConfig, MyModuleInitializer) - */ -#define E2D_REGISTER_MODULE(ConfigClass, InitializerClass) \ - namespace { \ - static const ::extra2d::ModuleId E2D_ANONYMOUS_VAR(module_id_) = \ - ::extra2d::ModuleRegistry::instance().registerModule( \ - ::extra2d::makeUnique(), \ - []() -> ::extra2d::UniquePtr<::extra2d::IModuleInitializer> { \ - return ::extra2d::makeUnique(); \ - } \ - ); \ - } - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/core/module.h b/Extra2D/include/extra2d/core/module.h new file mode 100644 index 0000000..02fcc33 --- /dev/null +++ b/Extra2D/include/extra2d/core/module.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include + +namespace extra2d { + +class Application; + +/** + * @brief 模块基类 + * 所有模块必须继承此类 + */ +class Module { +public: + virtual ~Module() = default; + + /** + * @brief 初始化模块 + * @return 初始化成功返回 true + */ + virtual bool init() = 0; + + /** + * @brief 关闭模块 + */ + virtual void shutdown() = 0; + + /** + * @brief 检查模块是否已初始化 + * @return 已初始化返回 true + */ + virtual bool ok() const = 0; + + /** + * @brief 获取模块名称 + * @return 模块名称 + */ + virtual const char* name() const = 0; + + /** + * @brief 获取模块优先级(数值越小越优先) + * @return 优先级值 + */ + virtual int priority() const { return 100; } + + /** + * @brief 获取模块依赖列表 + * @return 依赖模块类型列表 + */ + virtual std::vector deps() const { return {}; } + + /** + * @brief 设置所属Application + * @param app Application指针 + */ + void setApp(class Application* app) { app_ = app; } + + /** + * @brief 获取Application + * @return Application指针 + */ + class Application* app() const { return app_; } + +protected: + class Application* app_ = nullptr; +}; + +/** + * @brief 模块工厂函数类型 + */ +using ModuleFactory = std::function()>; + +} // namespace extra2d diff --git a/Extra2D/include/extra2d/core/registry.h b/Extra2D/include/extra2d/core/registry.h new file mode 100644 index 0000000..8196e67 --- /dev/null +++ b/Extra2D/include/extra2d/core/registry.h @@ -0,0 +1,116 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +class Application; + +/** + * @brief 模块注册表 + * 管理模块的注册、拓扑排序和生命周期 + */ +class Registry { +public: + static Registry& instance(); + + Registry(const Registry&) = delete; + Registry& operator=(const Registry&) = delete; + + /** + * @brief 注册模块 + * @tparam T 模块类型 + * @tparam Args 构造函数参数类型 + * @param args 构造函数参数 + * @return 模块指针 + */ + template + T* use(Args&&... args) { + static_assert(std::is_base_of_v, "T must derive from Module"); + + auto typeIdx = std::type_index(typeid(T)); + if (modules_.count(typeIdx)) { + return static_cast(modules_[typeIdx].get()); + } + + auto module = makeUnique(std::forward(args)...); + T* ptr = module.get(); + module->setApp(app_); + modules_[typeIdx] = std::move(module); + return ptr; + } + + /** + * @brief 获取模块 + * @tparam T 模块类型 + * @return 模块指针,不存在返回 nullptr + */ + template + T* get() const { + auto typeIdx = std::type_index(typeid(T)); + auto it = modules_.find(typeIdx); + if (it != modules_.end()) { + return static_cast(it->second.get()); + } + return nullptr; + } + + /** + * @brief 获取模块(基类版本) + * @param typeIdx 类型索引 + * @return 模块指针 + */ + Module* get(std::type_index typeIdx) const { + auto it = modules_.find(typeIdx); + if (it != modules_.end()) { + return it->second.get(); + } + return nullptr; + } + + /** + * @brief 设置Application + */ + void setApp(Application* app) { app_ = app; } + + /** + * @brief 初始化所有模块(按优先级拓扑排序) + * @return 初始化成功返回 true + */ + bool init(); + + /** + * @brief 关闭所有模块 + */ + void shutdown(); + + /** + * @brief 清空所有模块 + */ + void clear(); + + /** + * @brief 获取模块数量 + */ + size_t size() const { return modules_.size(); } + +private: + Registry() = default; + ~Registry() = default; + + /** + * @brief 拓扑排序模块 + * @return 排序后的模块列表 + */ + std::vector topologicalSort(); + + std::unordered_map> modules_; + Application* app_ = nullptr; +}; + +} // namespace extra2d diff --git a/Extra2D/include/extra2d/debug/debug_config.h b/Extra2D/include/extra2d/debug/debug_config.h deleted file mode 100644 index 0f3a5a7..0000000 --- a/Extra2D/include/extra2d/debug/debug_config.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include - -namespace extra2d { - -/** - * @file debug_config.h - * @brief 调试模块配置 - * - * 定义调试相关的配置数据结构,由 DebugModule 管理。 - */ - -/** - * @brief 调试配置数据结构 - */ -struct DebugConfigData { - bool enabled = false; - bool showFPS = false; - bool showMemoryUsage = false; - bool showRenderStats = false; - bool showColliders = false; - bool showGrid = false; - bool logToFile = false; - bool logToConsole = true; - int logLevel = 2; - bool breakOnAssert = true; - bool enableProfiling = false; - std::string logFilePath; - std::vector debugFlags; - - /** - * @brief 检查是否存在指定的调试标志 - * @param flag 要检查的标志名称 - * @return 如果存在返回 true - */ - bool hasDebugFlag(const std::string& flag) const; - - /** - * @brief 添加调试标志 - * @param flag 要添加的标志名称 - */ - void addDebugFlag(const std::string& flag); - - /** - * @brief 移除调试标志 - * @param flag 要移除的标志名称 - */ - void removeDebugFlag(const std::string& flag); -}; - -} diff --git a/Extra2D/include/extra2d/extra2d.h b/Extra2D/include/extra2d/extra2d.h index c9aa31b..b640f6b 100644 --- a/Extra2D/include/extra2d/extra2d.h +++ b/Extra2D/include/extra2d/extra2d.h @@ -7,14 +7,11 @@ #include #include #include +#include +#include // Config #include -#include -#include -#include -#include -#include #include #include @@ -23,21 +20,20 @@ #include #include #include -#include +#include #include // Graphics -#include -#include -#include -#include -#include - -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Scene #include @@ -52,7 +48,6 @@ #include // Utils -#include #include #include @@ -61,6 +56,7 @@ #include #include #include +#include // Application #include diff --git a/Extra2D/include/extra2d/graphics/camera.h b/Extra2D/include/extra2d/graphics/camera/camera.h similarity index 100% rename from Extra2D/include/extra2d/graphics/camera.h rename to Extra2D/include/extra2d/graphics/camera/camera.h diff --git a/Extra2D/include/extra2d/graphics/viewport_adapter.h b/Extra2D/include/extra2d/graphics/camera/viewport_adapter.h similarity index 100% rename from Extra2D/include/extra2d/graphics/viewport_adapter.h rename to Extra2D/include/extra2d/graphics/camera/viewport_adapter.h diff --git a/Extra2D/include/extra2d/graphics/render_backend.h b/Extra2D/include/extra2d/graphics/core/render_backend.h similarity index 100% rename from Extra2D/include/extra2d/graphics/render_backend.h rename to Extra2D/include/extra2d/graphics/core/render_backend.h diff --git a/Extra2D/include/extra2d/graphics/render_command.h b/Extra2D/include/extra2d/graphics/core/render_command.h similarity index 99% rename from Extra2D/include/extra2d/graphics/render_command.h rename to Extra2D/include/extra2d/graphics/core/render_command.h index 3caeb04..d2c3aa0 100644 --- a/Extra2D/include/extra2d/graphics/render_command.h +++ b/Extra2D/include/extra2d/graphics/core/render_command.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Extra2D/include/extra2d/graphics/core/render_module.h b/Extra2D/include/extra2d/graphics/core/render_module.h new file mode 100644 index 0000000..bb848bf --- /dev/null +++ b/Extra2D/include/extra2d/graphics/core/render_module.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 渲染模块 + * 管理渲染后端 + */ +class RenderModule : public Module { +public: + /** + * @brief 配置结构 + */ + struct Cfg { + BackendType backend; + int targetFPS; + bool vsync; + int multisamples; + int priority; + + Cfg() + : backend(BackendType::OpenGL) + , targetFPS(60) + , vsync(true) + , multisamples(0) + , priority(10) + {} + }; + + /** + * @brief 构造函数 + * @param cfg 配置 + */ + explicit RenderModule(const Cfg& cfg = Cfg{}); + + /** + * @brief 析构函数 + */ + ~RenderModule() override; + + bool init() override; + void shutdown() override; + bool ok() const override { return initialized_; } + const char* name() const override { return "render"; } + int priority() const override { return cfg_.priority; } + + /** + * @brief 获取依赖 + * @return 依赖模块类型列表 + */ + std::vector deps() const override { + return {std::type_index(typeid(WindowModule))}; + } + + /** + * @brief 获取渲染器 + * @return 渲染后端指针 + */ + RenderBackend* renderer() const { return renderer_.get(); } + +private: + Cfg cfg_; + UniquePtr renderer_; + bool initialized_ = false; +}; + +} // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/render_target.h b/Extra2D/include/extra2d/graphics/core/render_target.h similarity index 99% rename from Extra2D/include/extra2d/graphics/render_target.h rename to Extra2D/include/extra2d/graphics/core/render_target.h index 90b0ea2..47433a5 100644 --- a/Extra2D/include/extra2d/graphics/render_target.h +++ b/Extra2D/include/extra2d/graphics/core/render_target.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include namespace extra2d { diff --git a/Extra2D/include/extra2d/graphics/gpu_context.h b/Extra2D/include/extra2d/graphics/memory/gpu_context.h similarity index 100% rename from Extra2D/include/extra2d/graphics/gpu_context.h rename to Extra2D/include/extra2d/graphics/memory/gpu_context.h diff --git a/Extra2D/include/extra2d/graphics/vram_manager.h b/Extra2D/include/extra2d/graphics/memory/vram_manager.h similarity index 100% rename from Extra2D/include/extra2d/graphics/vram_manager.h rename to Extra2D/include/extra2d/graphics/memory/vram_manager.h diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_font_atlas.h b/Extra2D/include/extra2d/graphics/opengl/gl_font_atlas.h index a3e8d65..5b524aa 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_font_atlas.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_font_atlas.h @@ -3,9 +3,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h b/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h index b2bd972..4c369ea 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h @@ -1,8 +1,8 @@ #pragma once #include -#include -#include +#include +#include #include #include diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_shader.h b/Extra2D/include/extra2d/graphics/opengl/gl_shader.h index 3b01db1..f61c7b5 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_shader.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_shader.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_sprite_batch.h b/Extra2D/include/extra2d/graphics/opengl/gl_sprite_batch.h index 3c43cba..1609a2f 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_sprite_batch.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_sprite_batch.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_texture.h b/Extra2D/include/extra2d/graphics/opengl/gl_texture.h index 8d559a7..df9cd6d 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_texture.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_texture.h @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include +#include #include diff --git a/Extra2D/include/extra2d/graphics/render_config.h b/Extra2D/include/extra2d/graphics/render_config.h deleted file mode 100644 index 4af4996..0000000 --- a/Extra2D/include/extra2d/graphics/render_config.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace extra2d { - -/** - * @file render_config.h - * @brief 渲染模块配置 - * - * 定义渲染相关的配置数据结构,由 RenderModule 管理。 - */ - -/** - * @brief 渲染配置数据结构 - */ -struct RenderConfigData { - BackendType backend = BackendType::OpenGL; - int targetFPS = 60; - bool vsync = true; - bool tripleBuffering = false; - int multisamples = 0; - bool sRGBFramebuffer = false; - Color clearColor{0.0f, 0.0f, 0.0f, 1.0f}; - int maxTextureSize = 0; - int textureAnisotropy = 1; - bool wireframeMode = false; - bool depthTest = false; - bool blending = true; - bool dithering = false; - int spriteBatchSize = 1000; - int maxRenderTargets = 1; - bool allowShaderHotReload = false; - std::string shaderCachePath; - - /** - * @brief 检查是否启用多重采样 - * @return 如果多重采样数大于0返回 true - */ - bool isMultisampleEnabled() const { return multisamples > 0; } - - /** - * @brief 检查是否限制帧率 - * @return 如果设置了目标帧率返回 true - */ - bool isFPSCapped() const { return targetFPS > 0; } -}; - -} diff --git a/Extra2D/include/extra2d/graphics/render_module.h b/Extra2D/include/extra2d/graphics/render_module.h deleted file mode 100644 index 544bad1..0000000 --- a/Extra2D/include/extra2d/graphics/render_module.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace extra2d { - -class RenderModuleConfig : public IModuleConfig { -public: - BackendType backend = BackendType::OpenGL; - bool vsync = true; - int targetFPS = 60; - int multisamples = 0; - bool sRGBFramebuffer = false; - int spriteBatchSize = 1000; - - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.name = "Render"; - info.version = "1.0.0"; - info.priority = ModulePriority::Graphics; - info.enabled = true; - return info; - } - - std::string getConfigSectionName() const override { return "render"; } - - bool validate() const override; - void applyPlatformConstraints(PlatformType platform) override; - void resetToDefaults() override; - bool loadFromJson(const void* jsonData) override; - bool saveToJson(void* jsonData) const override; -}; - -class RenderModuleInitializer : public IModuleInitializer { -public: - RenderModuleInitializer(); - ~RenderModuleInitializer() override; - - ModuleId getModuleId() const override { return moduleId_; } - ModulePriority getPriority() const override { return ModulePriority::Graphics; } - std::vector getDependencies() const override; - - bool initialize(const IModuleConfig* config) override; - void shutdown() override; - bool isInitialized() const override { return initialized_; } - - void setModuleId(ModuleId id) { moduleId_ = id; } - void setWindow(IWindow* window) { window_ = window; } - - RenderBackend* getRenderer() const { return renderer_.get(); } - -private: - ModuleId moduleId_ = INVALID_MODULE_ID; - IWindow* window_ = nullptr; - UniquePtr renderer_; - bool initialized_ = false; -}; - -ModuleId get_render_module_id(); -void register_render_module(); - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/shader_cache.h b/Extra2D/include/extra2d/graphics/shader/shader_cache.h similarity index 100% rename from Extra2D/include/extra2d/graphics/shader_cache.h rename to Extra2D/include/extra2d/graphics/shader/shader_cache.h diff --git a/Extra2D/include/extra2d/graphics/shader_hot_reloader.h b/Extra2D/include/extra2d/graphics/shader/shader_hot_reloader.h similarity index 100% rename from Extra2D/include/extra2d/graphics/shader_hot_reloader.h rename to Extra2D/include/extra2d/graphics/shader/shader_hot_reloader.h diff --git a/Extra2D/include/extra2d/graphics/shader_interface.h b/Extra2D/include/extra2d/graphics/shader/shader_interface.h similarity index 100% rename from Extra2D/include/extra2d/graphics/shader_interface.h rename to Extra2D/include/extra2d/graphics/shader/shader_interface.h diff --git a/Extra2D/include/extra2d/graphics/shader_loader.h b/Extra2D/include/extra2d/graphics/shader/shader_loader.h similarity index 100% rename from Extra2D/include/extra2d/graphics/shader_loader.h rename to Extra2D/include/extra2d/graphics/shader/shader_loader.h diff --git a/Extra2D/include/extra2d/graphics/shader_manager.h b/Extra2D/include/extra2d/graphics/shader/shader_manager.h similarity index 97% rename from Extra2D/include/extra2d/graphics/shader_manager.h rename to Extra2D/include/extra2d/graphics/shader/shader_manager.h index ce34937..3bbc72e 100644 --- a/Extra2D/include/extra2d/graphics/shader_manager.h +++ b/Extra2D/include/extra2d/graphics/shader/shader_manager.h @@ -1,10 +1,10 @@ #pragma once #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/Extra2D/include/extra2d/graphics/shader_preset.h b/Extra2D/include/extra2d/graphics/shader/shader_preset.h similarity index 98% rename from Extra2D/include/extra2d/graphics/shader_preset.h rename to Extra2D/include/extra2d/graphics/shader/shader_preset.h index 18dd3fc..5014861 100644 --- a/Extra2D/include/extra2d/graphics/shader_preset.h +++ b/Extra2D/include/extra2d/graphics/shader/shader_preset.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include namespace extra2d { diff --git a/Extra2D/include/extra2d/graphics/alpha_mask.h b/Extra2D/include/extra2d/graphics/texture/alpha_mask.h similarity index 100% rename from Extra2D/include/extra2d/graphics/alpha_mask.h rename to Extra2D/include/extra2d/graphics/texture/alpha_mask.h diff --git a/Extra2D/include/extra2d/graphics/font.h b/Extra2D/include/extra2d/graphics/texture/font.h similarity index 100% rename from Extra2D/include/extra2d/graphics/font.h rename to Extra2D/include/extra2d/graphics/texture/font.h diff --git a/Extra2D/include/extra2d/graphics/texture.h b/Extra2D/include/extra2d/graphics/texture/texture.h similarity index 100% rename from Extra2D/include/extra2d/graphics/texture.h rename to Extra2D/include/extra2d/graphics/texture/texture.h diff --git a/Extra2D/include/extra2d/graphics/texture_atlas.h b/Extra2D/include/extra2d/graphics/texture/texture_atlas.h similarity index 99% rename from Extra2D/include/extra2d/graphics/texture_atlas.h rename to Extra2D/include/extra2d/graphics/texture/texture_atlas.h index 68b891b..975ef58 100644 --- a/Extra2D/include/extra2d/graphics/texture_atlas.h +++ b/Extra2D/include/extra2d/graphics/texture/texture_atlas.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Extra2D/include/extra2d/graphics/texture_pool.h b/Extra2D/include/extra2d/graphics/texture/texture_pool.h similarity index 99% rename from Extra2D/include/extra2d/graphics/texture_pool.h rename to Extra2D/include/extra2d/graphics/texture/texture_pool.h index 2bc517e..61edfdc 100644 --- a/Extra2D/include/extra2d/graphics/texture_pool.h +++ b/Extra2D/include/extra2d/graphics/texture/texture_pool.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/Extra2D/include/extra2d/input/input_config.h b/Extra2D/include/extra2d/input/input_config.h deleted file mode 100644 index 98924a6..0000000 --- a/Extra2D/include/extra2d/input/input_config.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -namespace extra2d { - -/** - * @file input_config.h - * @brief 输入模块配置 - * - * 定义输入相关的配置数据结构,由 InputModule 管理。 - */ - -/** - * @brief 输入配置数据结构 - */ -struct InputConfigData { - bool enabled = true; - bool rawMouseInput = false; - float mouseSensitivity = 1.0f; - bool invertMouseY = false; - bool invertMouseX = false; - float deadzone = 0.15f; - float triggerThreshold = 0.5f; - bool enableVibration = true; - int maxGamepads = 4; - bool autoConnectGamepads = true; - std::string gamepadMappingFile; - - /** - * @brief 验证死区值是否有效 - * @return 如果死区值在0-1范围内返回 true - */ - bool isDeadzoneValid() const { return deadzone >= 0.0f && deadzone <= 1.0f; } -}; - -} diff --git a/Extra2D/include/extra2d/platform/platform_module.h b/Extra2D/include/extra2d/platform/backend_factory.h similarity index 92% rename from Extra2D/include/extra2d/platform/platform_module.h rename to Extra2D/include/extra2d/platform/backend_factory.h index faeb144..b6b1b89 100644 --- a/Extra2D/include/extra2d/platform/platform_module.h +++ b/Extra2D/include/extra2d/platform/backend_factory.h @@ -10,16 +10,6 @@ namespace extra2d { -/** - * @brief 平台模块配置 - */ -struct PlatformModuleConfig { - std::string backend = "sdl2"; - bool gamepad = true; - bool touch = true; - float deadzone = 0.15f; -}; - /** * @brief 平台后端工厂 * 用于注册和创建平台后端 diff --git a/Extra2D/include/extra2d/platform/input_module.h b/Extra2D/include/extra2d/platform/input_module.h index d4e71ca..cbba615 100644 --- a/Extra2D/include/extra2d/platform/input_module.h +++ b/Extra2D/include/extra2d/platform/input_module.h @@ -1,129 +1,77 @@ #pragma once -#include -#include -#include +#include #include -#include +#include +#include namespace extra2d { /** - * @file input_module.h * @brief 输入模块 - * - * 输入模块管理键盘、鼠标、手柄和触摸输入。 - * 通过事件系统分发输入事件。 + * 管理输入设备 */ - -/** - * @brief 输入模块配置 - * 实现 IModuleConfig 接口 - */ -class InputModuleConfig : public IModuleConfig { +class InputModule : public Module { public: - InputConfigData inputConfig; - /** - * @brief 获取模块信息 - * @return 模块信息结构体 + * @brief 配置结构 */ - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.id = 0; - info.name = "Input"; - info.version = "1.0.0"; - info.priority = ModulePriority::Input; - info.enabled = true; - return info; - } + struct Cfg { + float deadzone; + float mouseSensitivity; + bool enableVibration; + int maxGamepads; + int priority; + + Cfg() + : deadzone(0.15f) + , mouseSensitivity(1.0f) + , enableVibration(true) + , maxGamepads(4) + , priority(20) + {} + }; /** - * @brief 获取配置节名称 - * @return 配置节名称字符串 + * @brief 构造函数 + * @param cfg 配置 */ - std::string getConfigSectionName() const override { return "input"; } + explicit InputModule(const Cfg& cfg = Cfg{}); /** - * @brief 验证配置有效性 - * @return 如果配置有效返回 true + * @brief 析构函数 */ - bool validate() const override; + ~InputModule() override; - /** - * @brief 应用平台约束 - * @param platform 目标平台类型 - */ - void applyPlatformConstraints(PlatformType platform) override; - - /** - * @brief 重置为默认配置 - */ - void resetToDefaults() override { - inputConfig = InputConfigData{}; - } - - /** - * @brief 从 JSON 数据加载配置 - * @param jsonData JSON 数据指针 - * @return 加载成功返回 true - */ - bool loadFromJson(const void* jsonData) override; - - /** - * @brief 保存配置到 JSON 数据 - * @param jsonData JSON 数据指针 - * @return 保存成功返回 true - */ - bool saveToJson(void* jsonData) const override; -}; - -/** - * @brief 输入模块初始化器 - * 实现 IModuleInitializer 接口 - */ -class InputModuleInitializer : public IModuleInitializer { -public: - InputModuleInitializer(); - ~InputModuleInitializer() override; - - ModuleId getModuleId() const override { return moduleId_; } - ModulePriority getPriority() const override { return ModulePriority::Input; } - std::vector getDependencies() const override; - bool initialize(const IModuleConfig* config) override; + bool init() override; void shutdown() override; - bool isInitialized() const override { return initialized_; } + bool ok() const override { return initialized_; } + const char* name() const override { return "input"; } + int priority() const override { return cfg_.priority; } - void setModuleId(ModuleId id) { moduleId_ = id; } + /** + * @brief 获取依赖 + * @return 依赖模块类型列表 + */ + std::vector deps() const override { + return {std::type_index(typeid(WindowModule))}; + } /** * @brief 获取输入接口 * @return 输入接口指针 */ - IInput* getInput() const { return input_; } + IInput* input() const { return input_; } /** * @brief 更新输入状态 - * 每帧调用,更新输入状态并分发事件 */ void update(); private: - ModuleId moduleId_ = INVALID_MODULE_ID; + Cfg cfg_; IInput* input_ = nullptr; bool initialized_ = false; - InputConfigData config_; }; -/** - * @brief 获取输入模块标识符 - * @return 输入模块标识符 - */ -ModuleId get_input_module_id(); - -/** - * @brief 注册输入模块 - */ -void register_input_module(); - -} +} // namespace extra2d diff --git a/Extra2D/include/extra2d/platform/platform_init_module.h b/Extra2D/include/extra2d/platform/platform_init_module.h deleted file mode 100644 index 26777ce..0000000 --- a/Extra2D/include/extra2d/platform/platform_init_module.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace extra2d { - -class PlatformModuleConfig : public IModuleConfig { -public: - PlatformType targetPlatform = PlatformType::Auto; - - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.id = 0; - info.name = "Platform"; - info.version = "1.0.0"; - info.priority = ModulePriority::Core; - info.enabled = true; - return info; - } - - std::string getConfigSectionName() const override { - return "platform"; - } - - bool validate() const override { - return true; - } - - void resetToDefaults() override { - targetPlatform = PlatformType::Auto; - } - - bool loadFromJson(const void* jsonData) override; - bool saveToJson(void* jsonData) const override; -}; - -class PlatformModuleInitializer : public IModuleInitializer { -public: - PlatformModuleInitializer(); - ~PlatformModuleInitializer() override; - - ModuleId getModuleId() const override { return moduleId_; } - ModulePriority getPriority() const override { return ModulePriority::Core; } - std::vector getDependencies() const override { return {}; } - - bool initialize(const IModuleConfig* config) override; - void shutdown() override; - bool isInitialized() const override { return initialized_; } - - void setModuleId(ModuleId id) { moduleId_ = id; } - void setPlatform(PlatformType platform) { targetPlatform_ = platform; } - - PlatformType getPlatform() const { return resolvedPlatform_; } - PlatformConfig* getPlatformConfig() const { return platformConfig_.get(); } - -private: - bool initSwitch(); - void shutdownSwitch(); - - ModuleId moduleId_ = INVALID_MODULE_ID; - bool initialized_ = false; - PlatformType targetPlatform_ = PlatformType::Auto; - PlatformType resolvedPlatform_ = PlatformType::Windows; - UniquePtr platformConfig_; -}; - -ModuleId get_platform_module_id(); -void register_platform_module(); - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/platform/window_module.h b/Extra2D/include/extra2d/platform/window_module.h index 3a11b09..ed5f69b 100644 --- a/Extra2D/include/extra2d/platform/window_module.h +++ b/Extra2D/include/extra2d/platform/window_module.h @@ -1,195 +1,67 @@ #pragma once -#include -#include +#include #include #include -#include namespace extra2d { /** - * @file window_module.h * @brief 窗口模块 - * - * 窗口模块使用 SDL2 作为唯一后端,支持以下平台: - * - Windows - * - Linux - * - macOS - * - Nintendo Switch + * 管理窗口创建和生命周期 */ - -/** - * @brief 窗口模块配置 - * 实现 IModuleConfig 接口 - */ -class WindowModuleConfig : public IModuleConfig { +class WindowModule : public Module { public: - WindowConfigData windowConfig; - /** - * @brief 获取模块信息 - * @return 模块信息结构体 + * @brief 配置结构 */ - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.id = 0; - info.name = "Window"; - info.version = "1.0.0"; - info.priority = ModulePriority::Core; - info.enabled = true; - return info; - } - - /** - * @brief 获取配置节名称 - * @return 配置节名称字符串 - */ - std::string getConfigSectionName() const override { - return "window"; - } - - /** - * @brief 验证配置有效性 - * @return 如果配置有效返回 true - */ - bool validate() const override { - return windowConfig.width > 0 && windowConfig.height > 0; - } - - /** - * @brief 应用平台约束 - * @param platform 目标平台类型 - */ - void applyPlatformConstraints(PlatformType platform) override; - - /** - * @brief 重置为默认配置 - */ - void resetToDefaults() override { - windowConfig = WindowConfigData{}; - } - - /** - * @brief 从 JSON 数据加载配置 - * @param jsonData JSON 数据指针 - * @return 加载成功返回 true - */ - bool loadFromJson(const void* jsonData) override; - - /** - * @brief 保存配置到 JSON 数据 - * @param jsonData JSON 数据指针 - * @return 保存成功返回 true - */ - bool saveToJson(void* jsonData) const override; -}; - -/** - * @brief 窗口模块初始化器 - * 实现 IModuleInitializer 接口 - */ -class WindowModuleInitializer : public IModuleInitializer { -public: + struct Cfg { + std::string title; + int w; + int h; + WindowMode mode; + bool vsync; + int priority; + std::string backend; + + Cfg() + : title("Extra2D") + , w(1280) + , h(720) + , mode(WindowMode::Windowed) + , vsync(true) + , priority(0) + , backend("sdl2") {} + }; + /** * @brief 构造函数 + * @param cfg 配置 */ - WindowModuleInitializer(); - + explicit WindowModule(const Cfg& cfg = Cfg()); + /** * @brief 析构函数 */ - ~WindowModuleInitializer() override; - - /** - * @brief 获取模块标识符 - * @return 模块唯一标识符 - */ - ModuleId getModuleId() const override { return moduleId_; } - - /** - * @brief 获取模块优先级 - * @return 模块优先级 - */ - ModulePriority getPriority() const override { return ModulePriority::Core; } - - /** - * @brief 获取模块依赖列表 - * @return 依赖模块标识符列表(窗口模块无依赖) - */ - std::vector getDependencies() const override { return {}; } - - /** - * @brief 初始化模块 - * @param config 模块配置指针 - * @return 初始化成功返回 true - */ - bool initialize(const IModuleConfig* config) override; - - /** - * @brief 关闭模块 - */ + ~WindowModule() override; + + bool init() override; void shutdown() override; - + bool ok() const override { return initialized_; } + const char* name() const override { return "window"; } + int priority() const override { return cfg_.priority; } + /** - * @brief 检查模块是否已初始化 - * @return 已初始化返回 true + * @brief 获取窗口 + * @return 窗口指针 */ - bool isInitialized() const override { return initialized_; } - - /** - * @brief 设置模块标识符 - * @param id 模块标识符 - */ - void setModuleId(ModuleId id) { moduleId_ = id; } - - /** - * @brief 设置窗口配置 - * @param config 窗口配置数据 - */ - void setWindowConfig(const WindowConfigData& config) { windowConfig_ = config; } - - /** - * @brief 获取窗口接口 - * @return 窗口接口指针 - */ - IWindow* getWindow() const { return window_.get(); } + IWindow* win() const { return win_.get(); } private: - /** - * @brief 初始化 SDL2 后端 - * @return 初始化成功返回 true - */ - bool initSDL2(); - - /** - * @brief 关闭 SDL2 后端 - */ - void shutdownSDL2(); - - /** - * @brief 创建窗口 - * @param config 窗口配置数据 - * @return 创建成功返回 true - */ - bool createWindow(const WindowConfigData& config); - - ModuleId moduleId_ = INVALID_MODULE_ID; + Cfg cfg_; + UniquePtr win_; bool initialized_ = false; - bool sdl2Initialized_ = false; - WindowConfigData windowConfig_; - UniquePtr window_; + bool sdlInited_ = false; }; -/** - * @brief 获取窗口模块标识符 - * @return 窗口模块标识符 - */ -ModuleId get_window_module_id(); - -/** - * @brief 注册窗口模块 - */ -void register_window_module(); - -} +} // namespace extra2d diff --git a/Extra2D/include/extra2d/resource/resource_config.h b/Extra2D/include/extra2d/resource/resource_config.h deleted file mode 100644 index 65aa2fe..0000000 --- a/Extra2D/include/extra2d/resource/resource_config.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include -#include - -namespace extra2d { - -/** - * @file resource_config.h - * @brief 资源模块配置 - * - * 定义资源相关的配置数据结构,由 ResourceModule 管理。 - */ - -/** - * @brief 资源配置数据结构 - */ -struct ResourceConfigData { - std::string assetRootPath = "assets"; - std::string cachePath = "cache"; - std::string savePath = "saves"; - std::string configPath = "config"; - std::string logPath = "logs"; - bool useAssetCache = true; - int maxCacheSize = 512; - bool hotReloadEnabled = false; - float hotReloadInterval = 1.0f; - bool compressTextures = false; - bool preloadCommonAssets = true; - std::vector searchPaths; - - /** - * @brief 添加资源搜索路径 - * @param path 要添加的搜索路径 - */ - void addSearchPath(const std::string& path); - - /** - * @brief 移除资源搜索路径 - * @param path 要移除的搜索路径 - */ - void removeSearchPath(const std::string& path); - - /** - * @brief 检查是否存在指定的搜索路径 - * @param path 要检查的路径 - * @return 如果存在返回 true - */ - bool hasSearchPath(const std::string& path) const; -}; - -} diff --git a/Extra2D/include/extra2d/scene/node.h b/Extra2D/include/extra2d/scene/node.h index 8a2cf86..45ec042 100644 --- a/Extra2D/include/extra2d/scene/node.h +++ b/Extra2D/include/extra2d/scene/node.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Extra2D/include/extra2d/scene/scene.h b/Extra2D/include/extra2d/scene/scene.h index 89b8b65..aad87cf 100644 --- a/Extra2D/include/extra2d/scene/scene.h +++ b/Extra2D/include/extra2d/scene/scene.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/Extra2D/include/extra2d/scene/sprite.h b/Extra2D/include/extra2d/scene/sprite.h index 185ac29..37c48ea 100644 --- a/Extra2D/include/extra2d/scene/sprite.h +++ b/Extra2D/include/extra2d/scene/sprite.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace extra2d { diff --git a/Extra2D/include/extra2d/scene/transition_box_scene.h b/Extra2D/include/extra2d/scene/transition_box_scene.h index 0a8a298..de9ed25 100644 --- a/Extra2D/include/extra2d/scene/transition_box_scene.h +++ b/Extra2D/include/extra2d/scene/transition_box_scene.h @@ -26,6 +26,7 @@ public: protected: void onTransitionStart() override; void renderContent(RenderBackend &renderer) override; + void updateTransition(float dt); private: int divisions_; diff --git a/Extra2D/include/extra2d/scene/transition_fade_scene.h b/Extra2D/include/extra2d/scene/transition_fade_scene.h index 41cd7c1..541bf26 100644 --- a/Extra2D/include/extra2d/scene/transition_fade_scene.h +++ b/Extra2D/include/extra2d/scene/transition_fade_scene.h @@ -34,6 +34,12 @@ protected: */ void onTransitionStart() override; + /** + * @brief 更新过渡进度 + * @param dt 帧间隔时间(秒) + */ + void updateTransition(float dt) override; + /** * @brief 渲染内容 * 根据进度控制新旧场景的显示 diff --git a/Extra2D/include/extra2d/scene/transition_flip_scene.h b/Extra2D/include/extra2d/scene/transition_flip_scene.h index 9a0122b..fa470ff 100644 --- a/Extra2D/include/extra2d/scene/transition_flip_scene.h +++ b/Extra2D/include/extra2d/scene/transition_flip_scene.h @@ -29,6 +29,7 @@ public: protected: void onTransitionStart() override; void renderContent(RenderBackend &renderer) override; + void updateTransition(float dt); private: Axis axis_; diff --git a/Extra2D/include/extra2d/scene/transition_scale_scene.h b/Extra2D/include/extra2d/scene/transition_scale_scene.h index 0f1972e..cad1948 100644 --- a/Extra2D/include/extra2d/scene/transition_scale_scene.h +++ b/Extra2D/include/extra2d/scene/transition_scale_scene.h @@ -24,6 +24,7 @@ public: protected: void onTransitionStart() override; void renderContent(RenderBackend &renderer) override; + void updateTransition(float dt); }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/transition_scene.h b/Extra2D/include/extra2d/scene/transition_scene.h index 93c9b2f..1e15e47 100644 --- a/Extra2D/include/extra2d/scene/transition_scene.h +++ b/Extra2D/include/extra2d/scene/transition_scene.h @@ -80,11 +80,22 @@ public: */ bool isFinished() const { return isFinished_; } + /** + * @brief 是否已取消 + */ + bool isCancelled() const { return isCancelled_; } + /** * @brief 完成过渡,通知 SceneManager 切换到目标场景 */ void finish(); + /** + * @brief 取消过渡 + * @param immediate 是否立即完成(false则回滚到原场景) + */ + void cancel(bool immediate = false); + // ------------------------------------------------------------------------ // 渲染 - 在 TransitionScene 上渲染新旧两个子场景 // ------------------------------------------------------------------------ @@ -113,15 +124,25 @@ protected: */ virtual void drawInScene(RenderBackend &renderer); + /** + * @brief 更新过渡进度(子类重写此方法更新动画) + * @param dt 帧间隔时间(秒) + */ + virtual void updateTransition(float dt); + float duration_; float elapsed_ = 0.0f; float progress_ = 0.0f; bool isFinished_ = false; + bool isCancelled_ = false; Ptr inScene_; // 要进入的场景 Ptr outScene_; // 要退出的场景 FinishCallback finishCallback_; + FinishCallback cancelCallback_; // 取消回调 + + friend class SceneManager; }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/transition_slide_scene.h b/Extra2D/include/extra2d/scene/transition_slide_scene.h index f41e490..7775182 100644 --- a/Extra2D/include/extra2d/scene/transition_slide_scene.h +++ b/Extra2D/include/extra2d/scene/transition_slide_scene.h @@ -27,6 +27,7 @@ public: protected: void onTransitionStart() override; void renderContent(RenderBackend &renderer) override; + void updateTransition(float dt); private: TransitionDirection direction_; diff --git a/Extra2D/include/extra2d/services/camera_service.h b/Extra2D/include/extra2d/services/camera_service.h index 5143377..948a187 100644 --- a/Extra2D/include/extra2d/services/camera_service.h +++ b/Extra2D/include/extra2d/services/camera_service.h @@ -1,8 +1,8 @@ #pragma once #include -#include -#include +#include +#include namespace extra2d { diff --git a/Extra2D/include/extra2d/services/logger_service.h b/Extra2D/include/extra2d/services/logger_service.h new file mode 100644 index 0000000..12a1245 --- /dev/null +++ b/Extra2D/include/extra2d/services/logger_service.h @@ -0,0 +1,228 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 日志级别枚举 + */ +enum class LogLevel { + Trace = 0, + Debug = 1, + Info = 2, + Warn = 3, + Error = 4, + Fatal = 5, + Off = 6 +}; + +/** + * @brief 日志服务接口 + */ +class ILogger : public IService { +public: + virtual ~ILogger() = default; + + /** + * @brief 设置日志级别 + */ + virtual void setLevel(LogLevel level) = 0; + + /** + * @brief 获取日志级别 + */ + virtual LogLevel getLevel() const = 0; + + /** + * @brief 检查日志级别是否启用 + */ + virtual bool isEnabled(LogLevel level) const = 0; + + /** + * @brief 记录日志(格式化) + */ + virtual void log(LogLevel level, const char* fmt, ...) = 0; + + /** + * @brief 记录日志(字符串) + */ + virtual void log(LogLevel level, const std::string& msg) = 0; + + /** + * @brief Trace级别日志 + */ + virtual void trace(const char* fmt, ...) = 0; + + /** + * @brief Debug级别日志 + */ + virtual void debug(const char* fmt, ...) = 0; + + /** + * @brief Info级别日志 + */ + virtual void info(const char* fmt, ...) = 0; + + /** + * @brief Warn级别日志 + */ + virtual void warn(const char* fmt, ...) = 0; + + /** + * @brief Error级别日志 + */ + virtual void error(const char* fmt, ...) = 0; + + /** + * @brief Fatal级别日志 + */ + virtual void fatal(const char* fmt, ...) = 0; + + ServiceInfo getServiceInfo() const override { + ServiceInfo info; + info.name = "Logger"; + info.priority = ServicePriority::Core; + info.enabled = true; + return info; + } +}; + +/** + * @brief 控制台日志服务实现 + */ +class ConsoleLogger : public ILogger { +public: + ConsoleLogger(); + ~ConsoleLogger() override; + + bool initialize() override; + void shutdown() override; + + void setLevel(LogLevel level) override; + LogLevel getLevel() const override; + bool isEnabled(LogLevel level) const override; + + void log(LogLevel level, const char* fmt, ...) override; + void log(LogLevel level, const std::string& msg) override; + + void trace(const char* fmt, ...) override; + void debug(const char* fmt, ...) override; + void info(const char* fmt, ...) override; + void warn(const char* fmt, ...) override; + void error(const char* fmt, ...) override; + void fatal(const char* fmt, ...) override; + +private: + void output(LogLevel level, const char* msg); + const char* getLevelString(LogLevel level); + + LogLevel level_; + class Impl; + UniquePtr impl_; +}; + +} // namespace extra2d + +// 格式化辅助函数 - 将参数转换为字符串 +namespace extra2d { +namespace detail { + template + std::string to_string(T&& value) { + using Decayed = std::decay_t; + if constexpr (std::is_same_v) { + return value; + } else if constexpr (std::is_same_v) { + return value ? value : "(null)"; + } else if constexpr (std::is_arithmetic_v) { + if constexpr (std::is_same_v) { + return value ? "true" : "false"; + } else if constexpr (std::is_floating_point_v) { + return std::to_string(value); + } else { + return std::to_string(value); + } + } else { + return ""; + } + } + + inline void format_impl(std::string& result, const char* fmt) { + result += fmt; + } + + template + void format_impl(std::string& result, const char* fmt, T&& value, Args&&... args) { + const char* p = fmt; + while (*p) { + if (*p == '{' && *(p + 1) == '}') { + result += to_string(std::forward(value)); + format_impl(result, p + 2, std::forward(args)...); + return; + } + result += *p++; + } + // 没有更多的 {},追加剩余参数(不应该发生) + result += " "; + result += to_string(std::forward(value)); + format_impl(result, p, std::forward(args)...); + } +} + +template +std::string format_str(const char* fmt, Args&&... args) { + if constexpr (sizeof...(args) == 0) { + return std::string(fmt); + } else { + std::string result; + detail::format_impl(result, fmt, std::forward(args)...); + return result; + } +} +} + +// 便捷宏 - 自动获取日志服务 +#define E2D_LOG(level, ...) \ + do { \ + if (auto logService = ::extra2d::ServiceLocator::instance().tryGetService<::extra2d::ILogger>()) { \ + if (logService->isEnabled(level)) { \ + logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \ + } \ + } \ + } while(0) + +#define E2D_LOG_TRACE(...) \ + E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__) + +#define E2D_LOG_DEBUG(...) \ + E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__) + +#define E2D_LOG_INFO(...) \ + E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__) + +#define E2D_LOG_WARN(...) \ + E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__) + +#define E2D_LOG_ERROR(...) \ + E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__) + +#define E2D_LOG_FATAL(...) \ + E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__) + +// 简写宏 +#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__) +#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__) +#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__) +#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__) + +#ifdef E2D_DEBUG + #define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) + #define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) +#else + #define E2D_DEBUG_LOG(...) + #define E2D_TRACE(...) +#endif diff --git a/Extra2D/include/extra2d/utils/logger.h b/Extra2D/include/extra2d/utils/logger.h index 43a91f4..086f3f9 100644 --- a/Extra2D/include/extra2d/utils/logger.h +++ b/Extra2D/include/extra2d/utils/logger.h @@ -1,201 +1,12 @@ #pragma once -#include -#include -#include -#include -#include +/** + * @file logger.h + * @brief 日志工具头文件 + * + * 提供便捷的日志宏定义,实际实现位于 logger_service.h + */ -namespace extra2d { +#include +#include -enum class LogLevel { - Trace = 0, - Debug = 1, - Info = 2, - Warn = 3, - Error = 4, - Fatal = 5, - Off = 6 -}; - -namespace detail { - -template inline std::string to_string_arg(const T &value) { - if constexpr (std::is_same_v) { - return value; - } else if constexpr (std::is_same_v || - std::is_same_v) { - return value ? std::string(value) : std::string("(null)"); - } else if constexpr (std::is_same_v) { - return value ? "true" : "false"; - } else if constexpr (std::is_arithmetic_v) { - if constexpr (std::is_floating_point_v) { - char buf[64]; - snprintf(buf, sizeof(buf), "%.2f", static_cast(value)); - return buf; - } else { - return std::to_string(value); - } - } else { - std::ostringstream oss; - oss << value; - return oss.str(); - } -} - -inline std::string format_impl(const char *fmt) { - std::string result; - while (*fmt) { - if (*fmt == '{' && *(fmt + 1) == '}') { - result += "{}"; - fmt += 2; - } else { - result += *fmt; - ++fmt; - } - } - return result; -} - -template -inline std::string format_impl(const char *fmt, const T &first, - const Args &...rest) { - std::string result; - while (*fmt) { - if (*fmt == '{') { - if (*(fmt + 1) == '}') { - result += to_string_arg(first); - fmt += 2; - result += format_impl(fmt, rest...); - return result; - } else if (*(fmt + 1) == ':') { - const char *end = fmt + 2; - while (*end && *end != '}') - ++end; - if (*end == '}') { - std::string spec(fmt + 2, end); - if (spec.find('x') != std::string::npos || - spec.find('X') != std::string::npos) { - if constexpr (std::is_integral_v) { - char buf[32]; - snprintf(buf, sizeof(buf), "0x%x", - static_cast(first)); - result += buf; - } else { - result += to_string_arg(first); - } - } else if (spec.find('f') != std::string::npos || - spec.find('.') != std::string::npos) { - if constexpr (std::is_arithmetic_v) { - int precision = 2; - auto dot = spec.find('.'); - if (dot != std::string::npos) { - precision = 0; - for (size_t i = dot + 1; - i < spec.size() && spec[i] >= '0' && spec[i] <= '9'; ++i) { - precision = precision * 10 + (spec[i] - '0'); - } - } - char fmtbuf[16]; - snprintf(fmtbuf, sizeof(fmtbuf), "%%.%df", precision); - char buf[64]; - snprintf(buf, sizeof(buf), fmtbuf, static_cast(first)); - result += buf; - } else { - result += to_string_arg(first); - } - } else { - result += to_string_arg(first); - } - fmt = end + 1; - result += format_impl(fmt, rest...); - return result; - } - } - } - result += *fmt; - ++fmt; - } - return result; -} - -} // namespace detail - -template -inline std::string e2d_format(const char *fmt, const Args &...args) { - return detail::format_impl(fmt, args...); -} - -inline std::string e2d_format(const char *fmt) { return std::string(fmt); } - -class Logger { -public: - static void init(); - static void shutdown(); - - static void setLevel(LogLevel level); - static void setConsoleOutput(bool enable); - static void setFileOutput(const std::string &filename); - - static LogLevel getLevel() { return level_; } - - template - static void log(LogLevel level, const char *fmt, const Args &...args) { - if (static_cast(level) < static_cast(level_)) - return; - std::string msg = e2d_format(fmt, args...); - outputLog(level, msg.c_str()); - } - - static void log(LogLevel level, const char *msg) { - if (static_cast(level) < static_cast(level_)) - return; - outputLog(level, msg); - } - -private: - static void outputLog(LogLevel level, const char *msg); - static const char *getLevelString(LogLevel level); - static void writeToConsole(LogLevel level, const char *msg); - static void writeToFile(LogLevel level, const char *msg); - - static LogLevel level_; - static bool initialized_; - static bool consoleOutput_; - static bool fileOutput_; - static std::string logFile_; - static void *logFileHandle_; -}; - -#ifdef E2D_DEBUG -#define E2D_LOG_TRACE(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Trace, __VA_ARGS__) -#define E2D_LOG_DEBUG(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Debug, __VA_ARGS__) -#else -#define E2D_LOG_TRACE(...) -#define E2D_LOG_DEBUG(...) -#endif - -#define E2D_LOG_INFO(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Info, __VA_ARGS__) -#define E2D_LOG_WARN(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Warn, __VA_ARGS__) -#define E2D_LOG_ERROR(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Error, __VA_ARGS__) -#define E2D_LOG_FATAL(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Fatal, __VA_ARGS__) - -#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__) -#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__) -#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__) -#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__) -#ifdef E2D_DEBUG -#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) -#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) -#else -#define E2D_DEBUG_LOG(...) -#define E2D_TRACE(...) -#endif - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/utils/logger_module.h b/Extra2D/include/extra2d/utils/logger_module.h deleted file mode 100644 index 59831a7..0000000 --- a/Extra2D/include/extra2d/utils/logger_module.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace extra2d { - -class LoggerModuleConfig : public IModuleConfig { -public: - LogLevel logLevel = LogLevel::Info; - bool consoleOutput = true; - bool fileOutput = false; - std::string logFilePath; - - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.id = 0; - info.name = "Logger"; - info.version = "1.0.0"; - info.priority = ModulePriority::Core; - info.enabled = true; - return info; - } - - std::string getConfigSectionName() const override { - return "logger"; - } - - bool validate() const override { - return true; - } - - void resetToDefaults() override { - logLevel = LogLevel::Info; - consoleOutput = true; - fileOutput = false; - logFilePath.clear(); - } - - bool loadFromJson(const void* jsonData) override; - bool saveToJson(void* jsonData) const override; -}; - -class LoggerModuleInitializer : public IModuleInitializer { -public: - LoggerModuleInitializer(); - ~LoggerModuleInitializer() override; - - ModuleId getModuleId() const override { return moduleId_; } - ModulePriority getPriority() const override { return ModulePriority::Core; } - std::vector getDependencies() const override { return {}; } - - bool initialize(const IModuleConfig* config) override; - void shutdown() override; - bool isInitialized() const override { return initialized_; } - - void setModuleId(ModuleId id) { moduleId_ = id; } - -private: - ModuleId moduleId_ = INVALID_MODULE_ID; - bool initialized_ = false; -}; - -} // namespace extra2d diff --git a/Extra2D/src/app/application.cpp b/Extra2D/src/app/application.cpp index 4df5b1e..b2a5bb8 100644 --- a/Extra2D/src/app/application.cpp +++ b/Extra2D/src/app/application.cpp @@ -1,18 +1,17 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include +#include +#include +#include +#include +#include #include #include - +#include +#include +#include +#include #include #include @@ -21,391 +20,249 @@ namespace extra2d { static double getTimeSeconds() { #ifdef __SWITCH__ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return static_cast(ts.tv_sec) + - static_cast(ts.tv_nsec) / 1000000000.0; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) + + static_cast(ts.tv_nsec) / 1000000000.0; #else - using namespace std::chrono; - auto now = steady_clock::now(); - auto duration = now.time_since_epoch(); - return duration_cast>(duration).count(); + using namespace std::chrono; + auto now = steady_clock::now(); + auto duration = now.time_since_epoch(); + return duration_cast>(duration).count(); #endif } -Application &Application::get() { - static Application instance; - return instance; +Application& Application::get() { + static Application instance; + return instance; } -bool Application::init() { - AppConfig cfg; - return init(cfg); -} - -bool Application::init(const AppConfig &config) { - if (initialized_) { - return true; - } - - register_config_module(); - register_platform_module(); - register_window_module(); - register_input_module(); - register_render_module(); - - auto *configInit = - ModuleRegistry::instance().getInitializer(get_config_module_id()); - if (configInit) { - auto *cfgInit = dynamic_cast(configInit); - if (cfgInit) { - cfgInit->setAppConfig(config); - } - } - - return initModules(); -} - -bool Application::init(const std::string &configPath) { - if (initialized_) { - return true; - } - - register_config_module(); - register_platform_module(); - register_window_module(); - register_input_module(); - register_render_module(); - - auto *configInit = - ModuleRegistry::instance().getInitializer(get_config_module_id()); - if (configInit) { - auto *cfgInit = dynamic_cast(configInit); - if (cfgInit) { - cfgInit->setConfigPath(configPath); - } - } - - return initModules(); -} - -void Application::registerCoreServices() { - auto &locator = ServiceLocator::instance(); - - if (!locator.hasService()) { - locator.registerService(makeShared()); - } - - if (!locator.hasService()) { - locator.registerService(makeShared()); - } - - if (!locator.hasService()) { - auto cameraService = makeShared(); - if (window_) { - cameraService->setViewport(0, static_cast(window_->width()), - static_cast(window_->height()), 0); - ViewportConfig vpConfig; - vpConfig.logicWidth = static_cast(window_->width()); - vpConfig.logicHeight = static_cast(window_->height()); - vpConfig.mode = ViewportMode::AspectRatio; - cameraService->setViewportConfig(vpConfig); - cameraService->updateViewport(window_->width(), window_->height()); - } - locator.registerService(cameraService); - } -} - -bool Application::initModules() { - auto &locator = ServiceLocator::instance(); - - if (!locator.hasService()) { - locator.registerService(makeShared()); - } - - auto initOrder = ModuleRegistry::instance().getInitializationOrder(); - - for (ModuleId moduleId : initOrder) { - auto *initializer = ModuleRegistry::instance().getInitializer(moduleId); - if (!initializer) { - continue; - } - - auto *moduleConfig = ModuleRegistry::instance().getModuleConfig(moduleId); - if (!moduleConfig) { - continue; - } - - auto info = moduleConfig->getModuleInfo(); - if (!info.enabled) { - continue; - } - - if (info.name == "Render") { - continue; - } - - if (!initializer->initialize(moduleConfig)) { - return false; - } - } - - auto *windowInit = - ModuleRegistry::instance().getInitializer(get_window_module_id()); - if (!windowInit || !windowInit->isInitialized()) { - return false; - } - - auto *windowModule = dynamic_cast(windowInit); - if (!windowModule) { - return false; - } - - window_ = windowModule->getWindow(); - if (!window_) { - return false; - } - - auto *renderInit = - ModuleRegistry::instance().getInitializer(get_render_module_id()); - if (renderInit) { - auto *renderModule = dynamic_cast(renderInit); - if (renderModule) { - renderModule->setWindow(window_); - - auto *renderConfig = - ModuleRegistry::instance().getModuleConfig(get_render_module_id()); - if (renderConfig && !renderInit->initialize(renderConfig)) { - return false; - } - } - } - - registerCoreServices(); - - if (!ServiceLocator::instance().initializeAll()) { - return false; - } - - auto cameraService = ServiceLocator::instance().getService(); - if (cameraService && window_) { - window_->onResize([cameraService](int width, int height) { - cameraService->updateViewport(width, height); - cameraService->applyViewportAdapter(); - - auto sceneService = - ServiceLocator::instance().getService(); - if (sceneService) { - auto currentScene = sceneService->getCurrentScene(); - if (currentScene) { - currentScene->setViewportSize(static_cast(width), - static_cast(height)); - } - } - }); - } - - initialized_ = true; - running_ = true; - - return true; -} - -void Application::shutdown() { - if (!initialized_) - return; - - VRAMMgr::get().printStats(); - - ServiceLocator::instance().clear(); - - window_ = nullptr; - - auto initOrder = ModuleRegistry::instance().getInitializationOrder(); - - for (auto it = initOrder.rbegin(); it != initOrder.rend(); ++it) { - ModuleId moduleId = *it; - auto *initializer = ModuleRegistry::instance().getInitializer(moduleId); - if (initializer && initializer->isInitialized()) { - initializer->shutdown(); - } - } - - initialized_ = false; - running_ = false; +Application::Application() { + Registry::instance().setApp(this); } Application::~Application() { - if (initialized_) { - shutdown(); - } + if (initialized_) { + shutdown(); + } +} + +bool Application::init() { + AppConfig cfg; + return init(cfg); +} + +bool Application::init(const AppConfig& config) { + if (initialized_) { + return true; + } + + appConfig_ = config; + + // 首先注册日志服务(模块初始化可能需要它) + auto& locator = ServiceLocator::instance(); + if (!locator.hasService()) { + auto logger = makeShared(); + locator.registerService(std::static_pointer_cast(logger)); + } + + // 初始化所有模块(拓扑排序) + if (!Registry::instance().init()) { + return false; + } + + // 模块初始化完成后,注册其他核心服务 + registerCoreServices(); + + initialized_ = true; + running_ = true; + return true; +} + +void Application::registerCoreServices() { + auto& locator = ServiceLocator::instance(); + + if (!locator.hasService()) { + auto service = makeShared(); + locator.registerService(std::static_pointer_cast(service)); + } + + if (!locator.hasService()) { + auto service = makeShared(); + locator.registerService(std::static_pointer_cast(service)); + } + + if (!locator.hasService()) { + auto service = makeShared(); + locator.registerService(std::static_pointer_cast(service)); + } + + auto* winMod = get(); + if (winMod && winMod->win() && !locator.hasService()) { + auto cameraService = makeShared(); + auto* win = winMod->win(); + cameraService->setViewport(0, static_cast(win->width()), + static_cast(win->height()), 0); + ViewportConfig vpConfig; + vpConfig.logicWidth = static_cast(win->width()); + vpConfig.logicHeight = static_cast(win->height()); + vpConfig.mode = ViewportMode::AspectRatio; + cameraService->setViewportConfig(vpConfig); + cameraService->updateViewport(win->width(), win->height()); + locator.registerService(std::static_pointer_cast(cameraService)); + + win->onResize([cameraService](int width, int height) { + cameraService->updateViewport(width, height); + cameraService->applyViewportAdapter(); + }); + } + + locator.initializeAll(); +} + +void Application::shutdown() { + if (!initialized_) return; + + VRAMMgr::get().printStats(); + + ServiceLocator::instance().clear(); + Registry::instance().shutdown(); + Registry::instance().clear(); + + initialized_ = false; + running_ = false; } void Application::run() { - if (!initialized_) { - return; - } - - lastFrameTime_ = getTimeSeconds(); - - while (running_ && !window_->shouldClose()) { - mainLoop(); - } + if (!initialized_) return; + + auto* winMod = get(); + if (!winMod || !winMod->win()) return; + + lastFrameTime_ = getTimeSeconds(); + + while (running_ && !winMod->win()->shouldClose()) { + mainLoop(); + } } void Application::quit() { - shouldQuit_ = true; - running_ = false; + shouldQuit_ = true; + running_ = false; } void Application::pause() { - if (!paused_) { - paused_ = true; - ServiceLocator::instance().pauseAll(); - } + if (!paused_) { + paused_ = true; + ServiceLocator::instance().pauseAll(); + } } void Application::resume() { - if (paused_) { - paused_ = false; - ServiceLocator::instance().resumeAll(); - lastFrameTime_ = getTimeSeconds(); - } + if (paused_) { + paused_ = false; + ServiceLocator::instance().resumeAll(); + lastFrameTime_ = getTimeSeconds(); + } } void Application::mainLoop() { - double currentTime = getTimeSeconds(); - deltaTime_ = static_cast(currentTime - lastFrameTime_); - lastFrameTime_ = currentTime; - - totalTime_ += deltaTime_; - - frameCount_++; - fpsTimer_ += deltaTime_; - if (fpsTimer_ >= 1.0f) { - currentFps_ = frameCount_; - frameCount_ = 0; - fpsTimer_ -= 1.0f; - } - - window_->poll(); - - auto eventService = ServiceLocator::instance().getService(); - if (eventService) { - eventService->processQueue(); - } - - if (!paused_) { - update(); - } - - render(); - - const auto &appConfig = ConfigManager::instance().appConfig(); - - auto *renderConfig = - ModuleRegistry::instance().getModuleConfig(get_render_module_id()); - auto *renderModuleConfig = - dynamic_cast(renderConfig); - - if (renderModuleConfig && !renderModuleConfig->vsync && - renderModuleConfig->targetFPS > 0) { - double frameEndTime = getTimeSeconds(); - double frameTime = frameEndTime - currentTime; - double target = 1.0 / static_cast(renderModuleConfig->targetFPS); - if (frameTime < target) { - auto sleepSeconds = target - frameTime; - std::this_thread::sleep_for(std::chrono::duration(sleepSeconds)); + double currentTime = getTimeSeconds(); + deltaTime_ = static_cast(currentTime - lastFrameTime_); + lastFrameTime_ = currentTime; + + totalTime_ += deltaTime_; + + frameCount_++; + fpsTimer_ += deltaTime_; + if (fpsTimer_ >= 1.0f) { + currentFps_ = frameCount_; + frameCount_ = 0; + fpsTimer_ -= 1.0f; + } + + auto* winMod = get(); + if (winMod && winMod->win()) { + winMod->win()->poll(); + } + + auto eventService = ServiceLocator::instance().getService(); + if (eventService) { + eventService->processQueue(); + } + + if (!paused_) { + update(); + } + + render(); + + // 帧率限制 + auto* renderMod = get(); + if (renderMod && renderMod->renderer()) { + // 这里可以添加帧率限制逻辑 } - } - - ConfigManager::instance().update(deltaTime_); } -void Application::update() { ServiceLocator::instance().updateAll(deltaTime_); } +void Application::update() { + ServiceLocator::instance().updateAll(deltaTime_); + + auto* inputMod = get(); + if (inputMod) { + inputMod->update(); + } +} void Application::render() { - auto *renderInit = - ModuleRegistry::instance().getInitializer(get_render_module_id()); - RenderBackend *renderer = nullptr; - if (renderInit) { - auto *renderModule = dynamic_cast(renderInit); - if (renderModule) { - renderer = renderModule->getRenderer(); + auto* renderMod = get(); + if (!renderMod || !renderMod->renderer()) return; + + auto* renderer = renderMod->renderer(); + auto* winMod = get(); + if (!winMod || !winMod->win()) return; + + auto cameraService = ServiceLocator::instance().getService(); + if (cameraService) { + const auto& vp = cameraService->getViewportResult().viewport; + renderer->setViewport( + static_cast(vp.origin.x), static_cast(vp.origin.y), + static_cast(vp.size.width), static_cast(vp.size.height)); + renderer->setViewProjection(cameraService->getViewProjectionMatrix()); + } else { + renderer->setViewport(0, 0, winMod->win()->width(), winMod->win()->height()); } - } - - if (!renderer) { - return; - } - - auto cameraService = ServiceLocator::instance().getService(); - if (cameraService) { - const auto &vp = cameraService->getViewportResult().viewport; - renderer->setViewport( - static_cast(vp.origin.x), static_cast(vp.origin.y), - static_cast(vp.size.width), static_cast(vp.size.height)); - - renderer->setViewProjection(cameraService->getViewProjectionMatrix()); - } else { - renderer->setViewport(0, 0, window_->width(), window_->height()); - } - - auto sceneService = ServiceLocator::instance().getService(); - if (sceneService) { - sceneService->render(*renderer); - } - - window_->swap(); -} - -IInput &Application::input() { return *window_->input(); } - -RenderBackend &Application::renderer() { - auto *renderInit = - ModuleRegistry::instance().getInitializer(get_render_module_id()); - if (renderInit) { - auto *renderModule = dynamic_cast(renderInit); - if (renderModule && renderModule->getRenderer()) { - return *renderModule->getRenderer(); + + auto sceneService = ServiceLocator::instance().getService(); + if (sceneService) { + sceneService->render(*renderer); } - } - static RenderBackend *dummy = nullptr; - if (!dummy) { - dummy = RenderBackend::create(BackendType::OpenGL).release(); - } - return *dummy; + + winMod->win()->swap(); } -SharedPtr Application::scenes() { - return ServiceLocator::instance().getService(); +IWindow* Application::window() { + auto* winMod = get(); + return winMod ? winMod->win() : nullptr; } -SharedPtr Application::timers() { - return ServiceLocator::instance().getService(); +RenderBackend* Application::renderer() { + auto* renderMod = get(); + return renderMod ? renderMod->renderer() : nullptr; } -SharedPtr Application::events() { - return ServiceLocator::instance().getService(); -} - -SharedPtr Application::camera() { - return ServiceLocator::instance().getService(); +IInput* Application::input() { + auto* winMod = get(); + return (winMod && winMod->win()) ? winMod->win()->input() : nullptr; } void Application::enterScene(Ptr scene) { - auto sceneService = ServiceLocator::instance().getService(); - if (sceneService && scene) { - scene->setViewportSize(static_cast(window_->width()), - static_cast(window_->height())); - sceneService->enterScene(scene); - } -} - -ConfigManager &Application::config() { return ConfigManager::instance(); } - -const AppConfig &Application::getConfig() const { - return ConfigManager::instance().appConfig(); + auto sceneService = ServiceLocator::instance().getService(); + auto* winMod = get(); + if (sceneService && scene && winMod && winMod->win()) { + scene->setViewportSize(static_cast(winMod->win()->width()), + static_cast(winMod->win()->height())); + sceneService->enterScene(scene); + } } } // namespace extra2d diff --git a/Extra2D/src/config/config_loader_ini.cpp b/Extra2D/src/config/config_loader_ini.cpp deleted file mode 100644 index 4826251..0000000 --- a/Extra2D/src/config/config_loader_ini.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace extra2d { - -/** - * @brief 去除字符串首尾空白字符 - * @param str 输入字符串 - * @return 去除空白后的字符串 - */ -static std::string trim(const std::string& str) { - size_t start = 0; - while (start < str.length() && std::isspace(static_cast(str[start]))) { - ++start; - } - size_t end = str.length(); - while (end > start && std::isspace(static_cast(str[end - 1]))) { - --end; - } - return str.substr(start, end - start); -} - -/** - * @brief 将字符串转换为小写 - * @param str 输入字符串 - * @return 小写字符串 - */ -static std::string toLower(const std::string& str) { - std::string result = str; - for (char& c : result) { - c = static_cast(std::tolower(static_cast(c))); - } - return result; -} - -/** - * @brief INI 数据存储结构 - */ -using IniData = std::map>; - -/** - * @brief 解析 INI 内容到数据结构 - * @param content INI 内容字符串 - * @param data 输出的 INI 数据 - * @return 解析结果 - */ -static ConfigLoadResult parseIniContent(const std::string& content, IniData& data) { - std::istringstream stream(content); - std::string line; - std::string currentSection; - int lineNumber = 0; - - while (std::getline(stream, line)) { - ++lineNumber; - line = trim(line); - - if (line.empty() || line[0] == ';' || line[0] == '#') { - continue; - } - - if (line[0] == '[') { - size_t endBracket = line.find(']'); - if (endBracket == std::string::npos) { - return ConfigLoadResult::error("INI 解析错误: 缺少右括号", lineNumber); - } - currentSection = trim(line.substr(1, endBracket - 1)); - if (data.find(currentSection) == data.end()) { - data[currentSection] = std::map(); - } - } else { - size_t equalPos = line.find('='); - if (equalPos == std::string::npos) { - continue; - } - - std::string key = trim(line.substr(0, equalPos)); - std::string value = trim(line.substr(equalPos + 1)); - - if (currentSection.empty()) { - return ConfigLoadResult::error("INI 解析错误: 键值对不在任何节中", lineNumber); - } - - data[currentSection][key] = value; - } - } - - return ConfigLoadResult::ok(); -} - -/** - * @brief 获取 INI 值(带默认值) - * @param data INI 数据 - * @param section 节名 - * @param key 键名 - * @param defaultValue 默认值 - * @return 值字符串 - */ -static std::string getIniValue(const IniData& data, const std::string& section, - const std::string& key, const std::string& defaultValue = "") { - auto sectionIt = data.find(section); - if (sectionIt == data.end()) { - return defaultValue; - } - auto keyIt = sectionIt->second.find(key); - if (keyIt == sectionIt->second.end()) { - return defaultValue; - } - return keyIt->second; -} - -/** - * @brief 检查 INI 值是否存在 - * @param data INI 数据 - * @param section 节名 - * @param key 键名 - * @return 是否存在 - */ -static bool hasIniValue(const IniData& data, const std::string& section, const std::string& key) { - auto sectionIt = data.find(section); - if (sectionIt == data.end()) { - return false; - } - return sectionIt->second.find(key) != sectionIt->second.end(); -} - -ConfigLoadResult IniConfigLoader::load(const std::string& filepath, AppConfig& config) { - E2D_LOG_INFO("正在从 INI 文件加载应用配置: {}", filepath); - - std::ifstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法打开配置文件: {}", filepath); - return ConfigLoadResult::error("无法打开配置文件: " + filepath); - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - file.close(); - - return loadFromString(content, config); -} - -ConfigSaveResult IniConfigLoader::save(const std::string& filepath, const AppConfig& config) { - E2D_LOG_INFO("正在保存应用配置到 INI 文件: {}", filepath); - - std::string content = saveToString(config); - - std::ofstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法创建配置文件: {}", filepath); - return ConfigSaveResult::error("无法创建配置文件: " + filepath); - } - - file << content; - file.close(); - - E2D_LOG_INFO("配置已成功保存到: {}", filepath); - return ConfigSaveResult::ok(); -} - -ConfigLoadResult IniConfigLoader::loadFromString(const std::string& content, AppConfig& config) { - IniData data; - auto result = parseIniContent(content, data); - if (result.hasError()) { - return result; - } - - if (hasIniValue(data, "app", "name")) { - config.appName = getIniValue(data, "app", "name"); - } - if (hasIniValue(data, "app", "version")) { - config.appVersion = getIniValue(data, "app", "version"); - } - if (hasIniValue(data, "app", "organization")) { - config.organization = getIniValue(data, "app", "organization"); - } - if (hasIniValue(data, "app", "configFile")) { - config.configFile = getIniValue(data, "app", "configFile"); - } - if (hasIniValue(data, "app", "targetPlatform")) { - int value; - auto res = parseInt(getIniValue(data, "app", "targetPlatform"), value, "app.targetPlatform"); - if (res.isOk()) { - config.targetPlatform = static_cast(value); - } - } - - E2D_LOG_INFO("INI 应用配置加载成功"); - return ConfigLoadResult::ok(); -} - -std::string IniConfigLoader::saveToString(const AppConfig& config) { - std::ostringstream oss; - - oss << "[app]\n"; - oss << "name=" << config.appName << "\n"; - oss << "version=" << config.appVersion << "\n"; - oss << "organization=" << config.organization << "\n"; - oss << "configFile=" << config.configFile << "\n"; - oss << "targetPlatform=" << static_cast(config.targetPlatform) << "\n"; - - return oss.str(); -} - -ConfigLoadResult IniConfigLoader::loadWithModules(const std::string& filepath) { - E2D_LOG_INFO("正在从 INI 文件加载完整配置(含模块): {}", filepath); - - std::ifstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法打开配置文件: {}", filepath); - return ConfigLoadResult::error("无法打开配置文件: " + filepath); - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - file.close(); - - IniData data; - auto result = parseIniContent(content, data); - if (result.hasError()) { - return result; - } - - auto& registry = ModuleRegistry::instance(); - auto moduleIds = registry.getAllModules(); - - for (ModuleId moduleId : moduleIds) { - IModuleConfig* moduleConfig = registry.getModuleConfig(moduleId); - if (!moduleConfig) continue; - - std::string sectionName = moduleConfig->getConfigSectionName(); - if (sectionName.empty()) continue; - - if (data.find(sectionName) != data.end()) { - E2D_LOG_DEBUG("加载模块 {} 的 INI 配置", moduleConfig->getModuleInfo().name); - } - } - - E2D_LOG_INFO("完整配置加载成功"); - return ConfigLoadResult::ok(); -} - -ConfigSaveResult IniConfigLoader::saveWithModules(const std::string& filepath) { - E2D_LOG_INFO("正在保存完整配置(含模块)到 INI 文件: {}", filepath); - - std::ostringstream oss; - - oss << saveToString(ConfigManager::instance().appConfig()); - - auto& registry = ModuleRegistry::instance(); - auto moduleIds = registry.getAllModules(); - - for (ModuleId moduleId : moduleIds) { - IModuleConfig* moduleConfig = registry.getModuleConfig(moduleId); - if (!moduleConfig) continue; - - std::string sectionName = moduleConfig->getConfigSectionName(); - if (sectionName.empty()) continue; - - oss << "\n[" << sectionName << "]\n"; - } - - std::ofstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法创建配置文件: {}", filepath); - return ConfigSaveResult::error("无法创建配置文件: " + filepath); - } - - file << oss.str(); - file.close(); - - E2D_LOG_INFO("完整配置已成功保存到: {}", filepath); - return ConfigSaveResult::ok(); -} - -bool IniConfigLoader::supportsFile(const std::string& filepath) const { - if (filepath.length() >= 4) { - std::string ext = filepath.substr(filepath.length() - 4); - for (char& c : ext) c = static_cast(std::tolower(c)); - return ext == ".ini"; - } - return false; -} - -UniquePtr IniConfigLoader::clone() const { - return makeUnique(); -} - -std::string IniConfigLoader::sectionKey(const std::string& section, const std::string& key) const { - return section + "." + key; -} - -ConfigLoadResult IniConfigLoader::parseInt(const std::string& value, int& result, const std::string& fieldName) { - try { - size_t pos; - result = std::stoi(value, &pos); - if (pos != value.length()) { - return ConfigLoadResult::error("无法解析整数值: " + value, -1, fieldName); - } - return ConfigLoadResult::ok(); - } catch (const std::exception& e) { - return ConfigLoadResult::error(std::string("解析整数失败: ") + e.what(), -1, fieldName); - } -} - -ConfigLoadResult IniConfigLoader::parseFloat(const std::string& value, float& result, const std::string& fieldName) { - try { - size_t pos; - result = std::stof(value, &pos); - if (pos != value.length()) { - return ConfigLoadResult::error("无法解析浮点数值: " + value, -1, fieldName); - } - return ConfigLoadResult::ok(); - } catch (const std::exception& e) { - return ConfigLoadResult::error(std::string("解析浮点数失败: ") + e.what(), -1, fieldName); - } -} - -ConfigLoadResult IniConfigLoader::parseBool(const std::string& value, bool& result, const std::string& fieldName) { - std::string lower = toLower(value); - if (lower == "true" || lower == "1" || lower == "yes" || lower == "on") { - result = true; - return ConfigLoadResult::ok(); - } - if (lower == "false" || lower == "0" || lower == "no" || lower == "off") { - result = false; - return ConfigLoadResult::ok(); - } - return ConfigLoadResult::error("无法解析布尔值: " + value, -1, fieldName); -} - -} diff --git a/Extra2D/src/config/config_loader_json.cpp b/Extra2D/src/config/config_loader_json.cpp deleted file mode 100644 index 03dcca6..0000000 --- a/Extra2D/src/config/config_loader_json.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -using json = nlohmann::json; - -namespace extra2d { - -ConfigLoadResult JsonConfigLoader::load(const std::string& filepath, AppConfig& config) { - E2D_LOG_INFO("正在从 JSON 文件加载应用配置: {}", filepath); - - std::ifstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法打开配置文件: {}", filepath); - return ConfigLoadResult::error("无法打开配置文件: " + filepath); - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - file.close(); - - return loadFromString(content, config); -} - -ConfigSaveResult JsonConfigLoader::save(const std::string& filepath, const AppConfig& config) { - E2D_LOG_INFO("正在保存应用配置到 JSON 文件: {}", filepath); - - std::string content = saveToString(config); - - std::ofstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法创建配置文件: {}", filepath); - return ConfigSaveResult::error("无法创建配置文件: " + filepath); - } - - file << content; - file.close(); - - E2D_LOG_INFO("配置已成功保存到: {}", filepath); - return ConfigSaveResult::ok(); -} - -ConfigLoadResult JsonConfigLoader::loadFromString(const std::string& content, AppConfig& config) { - json root; - - try { - root = json::parse(content); - } catch (const json::parse_error& e) { - E2D_LOG_ERROR("JSON 解析错误: {}", e.what()); - return ConfigLoadResult::error(std::string("JSON 解析错误: ") + e.what(), - static_cast(e.byte)); - } - - if (root.contains("appName") && root["appName"].is_string()) { - config.appName = root["appName"].get(); - } - - if (root.contains("appVersion") && root["appVersion"].is_string()) { - config.appVersion = root["appVersion"].get(); - } - - if (root.contains("organization") && root["organization"].is_string()) { - config.organization = root["organization"].get(); - } - - if (root.contains("configFile") && root["configFile"].is_string()) { - config.configFile = root["configFile"].get(); - } - - if (root.contains("targetPlatform") && root["targetPlatform"].is_number_integer()) { - config.targetPlatform = static_cast(root["targetPlatform"].get()); - } - - E2D_LOG_INFO("JSON 应用配置加载成功"); - return ConfigLoadResult::ok(); -} - -std::string JsonConfigLoader::saveToString(const AppConfig& config) { - json root; - - root["appName"] = config.appName; - root["appVersion"] = config.appVersion; - root["organization"] = config.organization; - root["configFile"] = config.configFile; - root["targetPlatform"] = static_cast(config.targetPlatform); - - return root.dump(4); -} - -ConfigLoadResult JsonConfigLoader::loadWithModules(const std::string& filepath) { - E2D_LOG_INFO("正在从 JSON 文件加载完整配置(含模块): {}", filepath); - - std::ifstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法打开配置文件: {}", filepath); - return ConfigLoadResult::error("无法打开配置文件: " + filepath); - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - file.close(); - - json root; - try { - root = json::parse(content); - } catch (const json::parse_error& e) { - E2D_LOG_ERROR("JSON 解析错误: {}", e.what()); - return ConfigLoadResult::error(std::string("JSON 解析错误: ") + e.what(), - static_cast(e.byte)); - } - - auto& registry = ModuleRegistry::instance(); - auto moduleIds = registry.getAllModules(); - - for (ModuleId moduleId : moduleIds) { - IModuleConfig* moduleConfig = registry.getModuleConfig(moduleId); - if (!moduleConfig) continue; - - std::string sectionName = moduleConfig->getConfigSectionName(); - if (sectionName.empty()) continue; - - if (root.contains(sectionName)) { - if (!moduleConfig->loadFromJson(&root[sectionName])) { - E2D_LOG_WARN("模块 {} 配置加载失败", moduleConfig->getModuleInfo().name); - } else { - E2D_LOG_DEBUG("模块 {} 配置加载成功", moduleConfig->getModuleInfo().name); - } - } - } - - E2D_LOG_INFO("完整配置加载成功"); - return ConfigLoadResult::ok(); -} - -ConfigSaveResult JsonConfigLoader::saveWithModules(const std::string& filepath) { - E2D_LOG_INFO("正在保存完整配置(含模块)到 JSON 文件: {}", filepath); - - json root; - - auto& registry = ModuleRegistry::instance(); - auto moduleIds = registry.getAllModules(); - - for (ModuleId moduleId : moduleIds) { - IModuleConfig* moduleConfig = registry.getModuleConfig(moduleId); - if (!moduleConfig) continue; - - std::string sectionName = moduleConfig->getConfigSectionName(); - if (sectionName.empty()) continue; - - json sectionJson; - if (moduleConfig->saveToJson(§ionJson)) { - root[sectionName] = sectionJson; - } - } - - std::ofstream file(filepath); - if (!file.is_open()) { - E2D_LOG_ERROR("无法创建配置文件: {}", filepath); - return ConfigSaveResult::error("无法创建配置文件: " + filepath); - } - - file << root.dump(4); - file.close(); - - E2D_LOG_INFO("完整配置已成功保存到: {}", filepath); - return ConfigSaveResult::ok(); -} - -bool JsonConfigLoader::supportsFile(const std::string& filepath) const { - if (filepath.length() >= 5) { - std::string ext = filepath.substr(filepath.length() - 5); - for (char& c : ext) c = static_cast(std::tolower(c)); - return ext == ".json"; - } - return false; -} - -UniquePtr JsonConfigLoader::clone() const { - return makeUnique(); -} - -} diff --git a/Extra2D/src/config/config_manager.cpp b/Extra2D/src/config/config_manager.cpp deleted file mode 100644 index 2094b22..0000000 --- a/Extra2D/src/config/config_manager.cpp +++ /dev/null @@ -1,385 +0,0 @@ -#include -#include -#include -#include -#include - -namespace extra2d { - -ConfigManager::ConfigManager() - : m_nextCallbackId(1) - , m_autoSaveEnabled(false) - , m_autoSaveInterval(30.0f) - , m_autoSaveTimer(0.0f) -{ - m_appConfig = AppConfig::createDefault(); -} - -ConfigManager::~ConfigManager() { - if (m_initialized) { - shutdown(); - } -} - -ConfigManager& ConfigManager::instance() { - static ConfigManager instance; - return instance; -} - -bool ConfigManager::initialize(const std::string& configPath) { - if (m_initialized) { - E2D_LOG_WARN("ConfigManager already initialized"); - return true; - } - - std::lock_guard lock(m_mutex); - - m_configPath = configPath; - - m_platformConfig = createPlatformConfig(PlatformType::Auto); - if (!m_platformConfig) { - E2D_LOG_ERROR("Failed to create platform config"); - return false; - } - - m_loader = makeUnique(); - if (!m_loader) { - E2D_LOG_ERROR("Failed to create config loader"); - return false; - } - - m_appConfig = AppConfig::createDefault(); - m_appConfig.targetPlatform = PlatformDetector::detect(); - - m_initialized = true; - m_modified = false; - - E2D_LOG_INFO("ConfigManager initialized for platform: {}", - m_platformConfig->platformName()); - return true; -} - -void ConfigManager::shutdown() { - if (!m_initialized) { - return; - } - - std::lock_guard lock(m_mutex); - - if (m_autoSaveEnabled && m_modified) { - saveConfig(); - } - - m_changeCallbacks.clear(); - m_rawValues.clear(); - m_loader.reset(); - m_platformConfig.reset(); - - m_initialized = false; - m_modified = false; - - E2D_LOG_INFO("ConfigManager shutdown complete"); -} - -bool ConfigManager::isInitialized() const { - return m_initialized; -} - -ConfigLoadResult ConfigManager::loadConfig(const std::string& filepath) { - std::lock_guard lock(m_mutex); - - std::string path = filepath.empty() ? m_configPath : filepath; - if (path.empty()) { - return ConfigLoadResult::error("No config file path specified"); - } - - if (!m_loader) { - return ConfigLoadResult::error("Config loader not initialized"); - } - - AppConfig loadedConfig; - ConfigLoadResult result = m_loader->load(path, loadedConfig); - - if (result.success) { - m_appConfig.merge(loadedConfig); - - if (!m_appConfig.validate()) { - E2D_LOG_WARN("Loaded config validation failed, using defaults"); - m_appConfig = AppConfig::createDefault(); - } - - m_configPath = path; - m_modified = false; - - E2D_LOG_INFO("Config loaded from: {}", path); - } else { - E2D_LOG_ERROR("Failed to load config from {}: {}", path, result.errorMessage); - } - - return result; -} - -ConfigSaveResult ConfigManager::saveConfig(const std::string& filepath) { - std::lock_guard lock(m_mutex); - - std::string path = filepath.empty() ? m_configPath : filepath; - if (path.empty()) { - return ConfigSaveResult::error("No config file path specified"); - } - - if (!m_loader) { - return ConfigSaveResult::error("Config loader not initialized"); - } - - ConfigSaveResult result = m_loader->save(path, m_appConfig); - - if (result.success) { - m_configPath = path; - m_modified = false; - - E2D_LOG_INFO("Config saved to: {}", path); - } else { - E2D_LOG_ERROR("Failed to save config to {}: {}", path, result.errorMessage); - } - - return result; -} - -ConfigLoadResult ConfigManager::loadConfigWithModules(const std::string& filepath) { - std::lock_guard lock(m_mutex); - - std::string path = filepath.empty() ? m_configPath : filepath; - if (path.empty()) { - return ConfigLoadResult::error("No config file path specified"); - } - - if (!m_loader) { - return ConfigLoadResult::error("Config loader not initialized"); - } - - ConfigLoadResult result = m_loader->loadWithModules(path); - - if (result.success) { - m_configPath = path; - m_modified = false; - E2D_LOG_INFO("Full config (with modules) loaded from: {}", path); - } else { - E2D_LOG_ERROR("Failed to load full config from {}: {}", path, result.errorMessage); - } - - return result; -} - -ConfigSaveResult ConfigManager::saveConfigWithModules(const std::string& filepath) { - std::lock_guard lock(m_mutex); - - std::string path = filepath.empty() ? m_configPath : filepath; - if (path.empty()) { - return ConfigSaveResult::error("No config file path specified"); - } - - if (!m_loader) { - return ConfigSaveResult::error("Config loader not initialized"); - } - - ConfigSaveResult result = m_loader->saveWithModules(path); - - if (result.success) { - m_configPath = path; - m_modified = false; - E2D_LOG_INFO("Full config (with modules) saved to: {}", path); - } else { - E2D_LOG_ERROR("Failed to save full config to {}: {}", path, result.errorMessage); - } - - return result; -} - -ConfigLoadResult ConfigManager::reload() { - return loadConfig(m_configPath); -} - -const AppConfig& ConfigManager::appConfig() const { - return m_appConfig; -} - -AppConfig& ConfigManager::appConfig() { - m_modified = true; - return m_appConfig; -} - -void ConfigManager::setAppConfig(const AppConfig& config) { - std::lock_guard lock(m_mutex); - - m_appConfig = config; - m_modified = true; - - E2D_LOG_INFO("App config updated"); -} - -PlatformConfig* ConfigManager::platformConfig() { - return m_platformConfig.get(); -} - -const PlatformConfig* ConfigManager::platformConfig() const { - return m_platformConfig.get(); -} - -int ConfigManager::registerChangeCallback(ConfigChangeCallback callback) { - std::lock_guard lock(m_mutex); - - int id = m_nextCallbackId++; - m_changeCallbacks[id] = std::move(callback); - - E2D_LOG_DEBUG("Registered config change callback with id {}", id); - return id; -} - -void ConfigManager::unregisterChangeCallback(int callbackId) { - std::lock_guard lock(m_mutex); - - auto it = m_changeCallbacks.find(callbackId); - if (it != m_changeCallbacks.end()) { - m_changeCallbacks.erase(it); - E2D_LOG_DEBUG("Unregistered config change callback {}", callbackId); - } -} - -void ConfigManager::clearChangeCallbacks() { - std::lock_guard lock(m_mutex); - m_changeCallbacks.clear(); - E2D_LOG_DEBUG("Cleared all config change callbacks"); -} - -void ConfigManager::setValue(const std::string& section, const std::string& key, const std::string& value) { - std::lock_guard lock(m_mutex); - - std::string fullKey = section + "." + key; - - ConfigChangeEvent event; - event.section = section; - event.field = key; - event.oldValue = m_rawValues[fullKey]; - event.newValue = value; - - m_rawValues[fullKey] = value; - m_modified = true; - notifyChangeCallbacks(event); -} - -void ConfigManager::setValue(const std::string& section, const std::string& key, int value) { - std::ostringstream oss; - oss << value; - setValue(section, key, oss.str()); -} - -void ConfigManager::setValue(const std::string& section, const std::string& key, float value) { - std::ostringstream oss; - oss << value; - setValue(section, key, oss.str()); -} - -void ConfigManager::setValue(const std::string& section, const std::string& key, bool value) { - setValue(section, key, std::string(value ? "true" : "false")); -} - -std::string ConfigManager::getValue(const std::string& section, const std::string& key, - const std::string& defaultValue) const { - std::lock_guard lock(m_mutex); - - std::string fullKey = section + "." + key; - auto it = m_rawValues.find(fullKey); - if (it != m_rawValues.end()) { - return it->second; - } - return defaultValue; -} - -int ConfigManager::getIntValue(const std::string& section, const std::string& key, int defaultValue) const { - std::string value = getValue(section, key); - if (!value.empty()) { - try { - return std::stoi(value); - } catch (...) { - return defaultValue; - } - } - return defaultValue; -} - -float ConfigManager::getFloatValue(const std::string& section, const std::string& key, float defaultValue) const { - std::string value = getValue(section, key); - if (!value.empty()) { - try { - return std::stof(value); - } catch (...) { - return defaultValue; - } - } - return defaultValue; -} - -bool ConfigManager::getBoolValue(const std::string& section, const std::string& key, bool defaultValue) const { - std::string value = getValue(section, key); - if (!value.empty()) { - if (value == "true" || value == "1") return true; - if (value == "false" || value == "0") return false; - } - return defaultValue; -} - -void ConfigManager::resetToDefaults() { - std::lock_guard lock(m_mutex); - - m_appConfig = AppConfig::createDefault(); - m_rawValues.clear(); - m_modified = true; - - E2D_LOG_INFO("Config reset to defaults"); -} - -bool ConfigManager::hasUnsavedChanges() const { - return m_modified; -} - -void ConfigManager::markModified() { - m_modified = true; -} - -void ConfigManager::clearModified() { - m_modified = false; -} - -void ConfigManager::setAutoSave(bool enabled, float interval) { - std::lock_guard lock(m_mutex); - - m_autoSaveEnabled = enabled; - m_autoSaveInterval = interval > 0.0f ? interval : 30.0f; - m_autoSaveTimer = 0.0f; - - E2D_LOG_INFO("Auto save {} (interval: {}s)", - enabled ? "enabled" : "disabled", m_autoSaveInterval); -} - -void ConfigManager::update(float deltaTime) { - if (!m_autoSaveEnabled || !m_modified) { - return; - } - - m_autoSaveTimer += deltaTime; - - if (m_autoSaveTimer >= m_autoSaveInterval) { - m_autoSaveTimer = 0.0f; - saveConfig(); - } -} - -void ConfigManager::notifyChangeCallbacks(const ConfigChangeEvent& event) { - for (const auto& pair : m_changeCallbacks) { - if (pair.second) { - pair.second(event); - } - } -} - -} diff --git a/Extra2D/src/config/config_module.cpp b/Extra2D/src/config/config_module.cpp deleted file mode 100644 index ea33fa7..0000000 --- a/Extra2D/src/config/config_module.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include -#include -#include - -using json = nlohmann::json; - -namespace extra2d { - -static ModuleId s_configModuleId = INVALID_MODULE_ID; - -ModuleId get_config_module_id() { - return s_configModuleId; -} - -bool ConfigModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("configPath")) { - configPath = j["configPath"].get(); - } - - return true; - } catch (...) { - return false; - } -} - -bool ConfigModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - j["configPath"] = configPath; - return true; - } catch (...) { - return false; - } -} - -ConfigModuleInitializer::ConfigModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , initialized_(false) { -} - -ConfigModuleInitializer::~ConfigModuleInitializer() { - if (initialized_) { - shutdown(); - } -} - -bool ConfigModuleInitializer::initialize(const IModuleConfig* config) { - if (initialized_) return true; - - const ConfigModuleConfig* configModule = dynamic_cast(config); - - if (!configPath_.empty()) { - if (!ConfigManager::instance().initialize(configPath_)) { - if (!ConfigManager::instance().initialize()) { - return false; - } - } - } else { - if (!ConfigManager::instance().initialize()) { - return false; - } - } - - if (configModule && !configModule->appConfig.appName.empty()) { - ConfigManager::instance().setAppConfig(configModule->appConfig); - } else if (!appConfig_.appName.empty()) { - ConfigManager::instance().setAppConfig(appConfig_); - } - - initialized_ = true; - E2D_LOG_INFO("Config module initialized"); - return true; -} - -void ConfigModuleInitializer::shutdown() { - if (!initialized_) return; - - E2D_LOG_INFO("Config module shutting down"); - ConfigManager::instance().shutdown(); - initialized_ = false; -} - -void register_config_module() { - if (s_configModuleId != INVALID_MODULE_ID) return; - - s_configModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_configModuleId); - return initializer; - } - ); -} - -namespace { - struct ConfigModuleAutoRegister { - ConfigModuleAutoRegister() { - register_config_module(); - } - }; - - static ConfigModuleAutoRegister s_autoRegister; -} - -} // namespace extra2d diff --git a/Extra2D/src/config/module_registry.cpp b/Extra2D/src/config/module_registry.cpp deleted file mode 100644 index 8c3ce77..0000000 --- a/Extra2D/src/config/module_registry.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include - -namespace extra2d { - -/** - * @brief 获取单例实例 - * 使用静态局部变量实现线程安全的单例模式 - * @return 模块注册表实例引用 - */ -ModuleRegistry& ModuleRegistry::instance() { - static ModuleRegistry instance; - return instance; -} - -/** - * @brief 注册模块 - * 将模块配置和初始化器工厂添加到注册表 - * @param config 模块配置 - * @param initializerFactory 初始化器工厂函数(可选) - * @return 分配的模块标识符 - */ -ModuleId ModuleRegistry::registerModule( - UniquePtr config, - ModuleInitializerFactory initializerFactory -) { - if (!config) { - std::fprintf(stderr, "[ERROR] Cannot register null module config\n"); - return INVALID_MODULE_ID; - } - - std::lock_guard lock(mutex_); - - ModuleInfo info = config->getModuleInfo(); - - if (nameToId_.find(info.name) != nameToId_.end()) { - std::fprintf(stderr, "[ERROR] Module '%s' already registered\n", info.name.c_str()); - return INVALID_MODULE_ID; - } - - ModuleId id = generateId(); - - ModuleEntry entry; - entry.id = id; - entry.config = std::move(config); - entry.initializerFactory = std::move(initializerFactory); - entry.initialized = false; - - modules_[id] = std::move(entry); - nameToId_[info.name] = id; - - return id; -} - -/** - * @brief 注销模块 - * 从注册表中移除指定模块 - * @param id 模块标识符 - * @return 注销成功返回 true - */ -bool ModuleRegistry::unregisterModule(ModuleId id) { - std::lock_guard lock(mutex_); - - auto it = modules_.find(id); - if (it == modules_.end()) { - return false; - } - - ModuleInfo info = it->second.config->getModuleInfo(); - nameToId_.erase(info.name); - modules_.erase(it); - - return true; -} - -/** - * @brief 获取模块配置 - * @param id 模块标识符 - * @return 模块配置指针,不存在返回 nullptr - */ -IModuleConfig* ModuleRegistry::getModuleConfig(ModuleId id) const { - std::lock_guard lock(mutex_); - - auto it = modules_.find(id); - if (it != modules_.end()) { - return it->second.config.get(); - } - return nullptr; -} - -/** - * @brief 根据名称获取模块配置 - * @param name 模块名称 - * @return 模块配置指针,不存在返回 nullptr - */ -IModuleConfig* ModuleRegistry::getModuleConfigByName(const std::string& name) const { - std::lock_guard lock(mutex_); - - auto nameIt = nameToId_.find(name); - if (nameIt == nameToId_.end()) { - return nullptr; - } - - auto moduleIt = modules_.find(nameIt->second); - if (moduleIt != modules_.end()) { - return moduleIt->second.config.get(); - } - return nullptr; -} - -/** - * @brief 获取或创建模块初始化器 - * @param id 模块标识符 - * @return 初始化器指针,不存在返回 nullptr - */ -IModuleInitializer* ModuleRegistry::getInitializer(ModuleId id) { - std::lock_guard lock(mutex_); - - auto it = modules_.find(id); - if (it == modules_.end() || !it->second.initializerFactory) { - return nullptr; - } - - if (!it->second.initializer) { - it->second.initializer = it->second.initializerFactory(); - } - - return it->second.initializer.get(); -} - -/** - * @brief 获取所有已注册模块标识符 - * @return 模块标识符列表 - */ -std::vector ModuleRegistry::getAllModules() const { - std::lock_guard lock(mutex_); - - std::vector result; - result.reserve(modules_.size()); - - for (const auto& pair : modules_) { - result.push_back(pair.first); - } - - return result; -} - -/** - * @brief 获取模块初始化顺序 - * 根据优先级和依赖关系计算初始化顺序 - * @return 按初始化顺序排列的模块标识符列表 - */ -std::vector ModuleRegistry::getInitializationOrder() const { - std::lock_guard lock(mutex_); - - std::vector> modulePriorities; - modulePriorities.reserve(modules_.size()); - - for (const auto& pair : modules_) { - ModuleInfo info = pair.second.config->getModuleInfo(); - if (info.enabled) { - modulePriorities.emplace_back(pair.first, static_cast(info.priority)); - } - } - - std::sort(modulePriorities.begin(), modulePriorities.end(), - [](const auto& a, const auto& b) { - return a.second < b.second; - }); - - std::vector result; - result.reserve(modulePriorities.size()); - - for (const auto& pair : modulePriorities) { - result.push_back(pair.first); - } - - return result; -} - -/** - * @brief 检查模块是否存在 - * @param id 模块标识符 - * @return 存在返回 true - */ -bool ModuleRegistry::hasModule(ModuleId id) const { - std::lock_guard lock(mutex_); - return modules_.find(id) != modules_.end(); -} - -/** - * @brief 清空所有注册的模块 - */ -void ModuleRegistry::clear() { - std::lock_guard lock(mutex_); - - modules_.clear(); - nameToId_.clear(); - nextId_ = 1; -} - -/** - * @brief 生成新的模块标识符 - * @return 新的模块标识符 - */ -ModuleId ModuleRegistry::generateId() { - return nextId_++; -} - -} diff --git a/Extra2D/src/core/registry.cpp b/Extra2D/src/core/registry.cpp new file mode 100644 index 0000000..f9eb1cb --- /dev/null +++ b/Extra2D/src/core/registry.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +Registry& Registry::instance() { + static Registry instance; + return instance; +} + +bool Registry::init() { + auto sorted = topologicalSort(); + + std::cout << "[Registry] Initializing " << sorted.size() << " modules..." << std::endl; + + for (auto* module : sorted) { + std::cout << "[Registry] Initializing module: " << module->name() << std::endl; + if (!module->init()) { + std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl; + return false; + } + std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl; + } + + std::cout << "[Registry] All modules initialized" << std::endl; + return true; +} + +void Registry::shutdown() { + auto sorted = topologicalSort(); + + // 反向关闭 + for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) { + (*it)->shutdown(); + } +} + +void Registry::clear() { + shutdown(); + modules_.clear(); +} + +std::vector Registry::topologicalSort() { + std::vector result; + std::unordered_map inDegree; + std::unordered_map> adj; + + // 构建图 + for (auto& [typeIdx, module] : modules_) { + inDegree[module.get()] = 0; + } + + for (auto& [typeIdx, module] : modules_) { + for (auto& depType : module->deps()) { + Module* dep = get(depType); + if (dep) { + adj[dep].push_back(module.get()); + inDegree[module.get()]++; + } + } + } + + // 优先级队列(优先级小的先处理) + auto cmp = [](Module* a, Module* b) { + return a->priority() > b->priority(); + }; + std::priority_queue, decltype(cmp)> pq(cmp); + + for (auto& [mod, degree] : inDegree) { + if (degree == 0) { + pq.push(mod); + } + } + + // 拓扑排序 + while (!pq.empty()) { + Module* curr = pq.top(); + pq.pop(); + result.push_back(curr); + + for (Module* next : adj[curr]) { + inDegree[next]--; + if (inDegree[next] == 0) { + pq.push(next); + } + } + } + + return result; +} + +} // namespace extra2d diff --git a/Extra2D/src/debug/debug_config.cpp b/Extra2D/src/debug/debug_config.cpp deleted file mode 100644 index 8345832..0000000 --- a/Extra2D/src/debug/debug_config.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -namespace extra2d { - -bool DebugConfigData::hasDebugFlag(const std::string& flag) const { - return std::find(debugFlags.begin(), debugFlags.end(), flag) != debugFlags.end(); -} - -void DebugConfigData::addDebugFlag(const std::string& flag) { - if (!hasDebugFlag(flag)) { - debugFlags.push_back(flag); - } -} - -void DebugConfigData::removeDebugFlag(const std::string& flag) { - auto it = std::find(debugFlags.begin(), debugFlags.end(), flag); - if (it != debugFlags.end()) { - debugFlags.erase(it); - } -} - -} diff --git a/Extra2D/src/graphics/camera.cpp b/Extra2D/src/graphics/camera/camera.cpp similarity index 98% rename from Extra2D/src/graphics/camera.cpp rename to Extra2D/src/graphics/camera/camera.cpp index 81a0383..23e074c 100644 --- a/Extra2D/src/graphics/camera.cpp +++ b/Extra2D/src/graphics/camera/camera.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include #include diff --git a/Extra2D/src/graphics/viewport_adapter.cpp b/Extra2D/src/graphics/camera/viewport_adapter.cpp similarity index 99% rename from Extra2D/src/graphics/viewport_adapter.cpp rename to Extra2D/src/graphics/camera/viewport_adapter.cpp index f2c4c01..fe6752a 100644 --- a/Extra2D/src/graphics/viewport_adapter.cpp +++ b/Extra2D/src/graphics/camera/viewport_adapter.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/Extra2D/src/graphics/render_backend.cpp b/Extra2D/src/graphics/core/render_backend.cpp similarity index 91% rename from Extra2D/src/graphics/render_backend.cpp rename to Extra2D/src/graphics/core/render_backend.cpp index d2dae52..7d4b53a 100644 --- a/Extra2D/src/graphics/render_backend.cpp +++ b/Extra2D/src/graphics/core/render_backend.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace extra2d { diff --git a/Extra2D/src/graphics/render_command.cpp b/Extra2D/src/graphics/core/render_command.cpp similarity index 99% rename from Extra2D/src/graphics/render_command.cpp rename to Extra2D/src/graphics/core/render_command.cpp index a3b6cef..dbfc6ba 100644 --- a/Extra2D/src/graphics/render_command.cpp +++ b/Extra2D/src/graphics/core/render_command.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace extra2d { diff --git a/Extra2D/src/graphics/core/render_module.cpp b/Extra2D/src/graphics/core/render_module.cpp new file mode 100644 index 0000000..220b2b9 --- /dev/null +++ b/Extra2D/src/graphics/core/render_module.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +RenderModule::RenderModule(const Cfg& cfg) : cfg_(cfg) {} + +RenderModule::~RenderModule() { + if (initialized_) { + shutdown(); + } +} + +static std::string getExecutableDir() { + char* basePath = SDL_GetBasePath(); + if (basePath) { + std::string path(basePath); + SDL_free(basePath); + return path; + } + return "./"; +} + +bool RenderModule::init() { + if (initialized_) return true; + + // 获取WindowModule依赖 + auto* winMod = Registry::instance().get(); + if (!winMod || !winMod->win()) { + return false; + } + + // 初始化ShaderManager + if (!ShaderManager::getInstance().isInitialized()) { + auto factory = makeShared(); + std::string shaderDir = getExecutableDir() + "shaders/"; + std::string cacheDir = getExecutableDir() + "shader_cache/"; + if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) { + E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}", shaderDir); + } + } + + // 创建渲染后端 + renderer_ = RenderBackend::create(cfg_.backend); + if (!renderer_) { + return false; + } + + // 初始化渲染器 + if (!renderer_->init(winMod->win())) { + renderer_.reset(); + return false; + } + + initialized_ = true; + return true; +} + +void RenderModule::shutdown() { + if (!initialized_) return; + + if (renderer_) { + renderer_->shutdown(); + renderer_.reset(); + } + + initialized_ = false; +} + +} // namespace extra2d diff --git a/Extra2D/src/graphics/render_target.cpp b/Extra2D/src/graphics/core/render_target.cpp similarity index 99% rename from Extra2D/src/graphics/render_target.cpp rename to Extra2D/src/graphics/core/render_target.cpp index f1f442a..931084d 100644 --- a/Extra2D/src/graphics/render_target.cpp +++ b/Extra2D/src/graphics/core/render_target.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #define STB_IMAGE_WRITE_IMPLEMENTATION diff --git a/Extra2D/src/graphics/gpu_context.cpp b/Extra2D/src/graphics/memory/gpu_context.cpp similarity index 95% rename from Extra2D/src/graphics/gpu_context.cpp rename to Extra2D/src/graphics/memory/gpu_context.cpp index 7d0a934..93684b7 100644 --- a/Extra2D/src/graphics/gpu_context.cpp +++ b/Extra2D/src/graphics/memory/gpu_context.cpp @@ -1,4 +1,4 @@ -#include +#include namespace extra2d { diff --git a/Extra2D/src/graphics/vram_manager.cpp b/Extra2D/src/graphics/memory/vram_manager.cpp similarity index 98% rename from Extra2D/src/graphics/vram_manager.cpp rename to Extra2D/src/graphics/memory/vram_manager.cpp index 93994c0..b8e11e4 100644 --- a/Extra2D/src/graphics/vram_manager.cpp +++ b/Extra2D/src/graphics/memory/vram_manager.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace extra2d { diff --git a/Extra2D/src/graphics/opengl/gl_renderer.cpp b/Extra2D/src/graphics/opengl/gl_renderer.cpp index 6452568..2e4a6d9 100644 --- a/Extra2D/src/graphics/opengl/gl_renderer.cpp +++ b/Extra2D/src/graphics/opengl/gl_renderer.cpp @@ -2,12 +2,12 @@ #include #include #include -#include +#include #include #include #include -#include -#include +#include +#include #include #include #include @@ -633,7 +633,7 @@ void GLRenderer::resetStats() { stats_ = Stats{}; } */ void GLRenderer::initShapeRendering() { // 从ShaderManager获取形状着色器 - shapeShader_ = ShaderManager::getInstance().getBuiltin("builtin_shape"); + shapeShader_ = ShaderManager::getInstance().getBuiltin("shape"); if (!shapeShader_) { E2D_LOG_WARN("Failed to get builtin shape shader, loading from manager"); if (!ShaderManager::getInstance().isInitialized()) { diff --git a/Extra2D/src/graphics/opengl/gl_texture.cpp b/Extra2D/src/graphics/opengl/gl_texture.cpp index 30e2682..e68b829 100644 --- a/Extra2D/src/graphics/opengl/gl_texture.cpp +++ b/Extra2D/src/graphics/opengl/gl_texture.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #define STB_IMAGE_IMPLEMENTATION #include #include diff --git a/Extra2D/src/graphics/render_module.cpp b/Extra2D/src/graphics/render_module.cpp deleted file mode 100644 index 11b9ad3..0000000 --- a/Extra2D/src/graphics/render_module.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -using json = nlohmann::json; - -namespace extra2d { - -static ModuleId s_renderModuleId = INVALID_MODULE_ID; - -ModuleId get_render_module_id() { - return s_renderModuleId; -} - -bool RenderModuleConfig::validate() const { - if (targetFPS < 1 || targetFPS > 240) { - return false; - } - - if (multisamples != 0 && multisamples != 2 && multisamples != 4 && - multisamples != 8 && multisamples != 16) { - return false; - } - - if (spriteBatchSize <= 0) { - return false; - } - - return true; -} - -void RenderModuleConfig::applyPlatformConstraints(PlatformType platform) { - switch (platform) { - case PlatformType::Switch: - if (multisamples > 4) { - multisamples = 4; - } - if (sRGBFramebuffer) { - sRGBFramebuffer = false; - } - if (targetFPS > 60) { - targetFPS = 60; - } - break; - default: - break; - } -} - -void RenderModuleConfig::resetToDefaults() { - backend = BackendType::OpenGL; - vsync = true; - targetFPS = 60; - multisamples = 0; - sRGBFramebuffer = false; - spriteBatchSize = 1000; -} - -bool RenderModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("backend")) { - std::string backendStr = j["backend"].get(); - if (backendStr == "opengl") { - backend = BackendType::OpenGL; - } - } - - if (j.contains("vsync")) { - vsync = j["vsync"].get(); - } - - if (j.contains("targetFPS")) { - targetFPS = j["targetFPS"].get(); - } - - if (j.contains("multisamples")) { - multisamples = j["multisamples"].get(); - } - - if (j.contains("sRGBFramebuffer")) { - sRGBFramebuffer = j["sRGBFramebuffer"].get(); - } - - if (j.contains("spriteBatchSize")) { - spriteBatchSize = j["spriteBatchSize"].get(); - } - - return true; - } catch (...) { - return false; - } -} - -bool RenderModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - j["backend"] = "opengl"; - j["vsync"] = vsync; - j["targetFPS"] = targetFPS; - j["multisamples"] = multisamples; - j["sRGBFramebuffer"] = sRGBFramebuffer; - j["spriteBatchSize"] = spriteBatchSize; - return true; - } catch (...) { - return false; - } -} - -RenderModuleInitializer::RenderModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , window_(nullptr) - , initialized_(false) { -} - -RenderModuleInitializer::~RenderModuleInitializer() { - if (initialized_) { - shutdown(); - } -} - -std::vector RenderModuleInitializer::getDependencies() const { - return {}; -} - -bool RenderModuleInitializer::initialize(const IModuleConfig* config) { - if (initialized_) return true; - - if (!config) return false; - - const RenderModuleConfig* renderConfig = dynamic_cast(config); - if (!renderConfig) return false; - - if (!renderConfig->validate()) return false; - - if (!window_) { - E2D_LOG_ERROR("Render module requires window to be set"); - return false; - } - - auto shaderFactory = std::make_shared(); - if (!ShaderManager::getInstance().init(shaderFactory, "extra2d")) { - E2D_LOG_WARN("Failed to initialize ShaderManager with default paths"); - } - - if (!ShaderManager::getInstance().loadBuiltinShaders()) { - E2D_LOG_WARN("Failed to load some builtin shaders"); - } - - renderer_ = RenderBackend::create(renderConfig->backend); - if (!renderer_) { - E2D_LOG_ERROR("Failed to create render backend"); - return false; - } - - if (!renderer_->init(window_)) { - E2D_LOG_ERROR("Failed to initialize renderer"); - renderer_.reset(); - return false; - } - - initialized_ = true; - E2D_LOG_INFO("Render module initialized"); - return true; -} - -void RenderModuleInitializer::shutdown() { - if (!initialized_) return; - - if (renderer_) { - renderer_->shutdown(); - renderer_.reset(); - } - - ShaderManager::getInstance().shutdown(); - - initialized_ = false; - E2D_LOG_INFO("Render module shutdown"); -} - -void register_render_module() { - if (s_renderModuleId != INVALID_MODULE_ID) return; - - s_renderModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_renderModuleId); - return initializer; - } - ); -} - -namespace { - struct RenderModuleAutoRegister { - RenderModuleAutoRegister() { - register_render_module(); - } - }; - - static RenderModuleAutoRegister s_autoRegister; -} - -} // namespace extra2d diff --git a/Extra2D/src/graphics/shader_cache.cpp b/Extra2D/src/graphics/shader/shader_cache.cpp similarity index 99% rename from Extra2D/src/graphics/shader_cache.cpp rename to Extra2D/src/graphics/shader/shader_cache.cpp index b77c61d..ca2a044 100644 --- a/Extra2D/src/graphics/shader_cache.cpp +++ b/Extra2D/src/graphics/shader/shader_cache.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Extra2D/src/graphics/shader_hot_reloader.cpp b/Extra2D/src/graphics/shader/shader_hot_reloader.cpp similarity index 98% rename from Extra2D/src/graphics/shader_hot_reloader.cpp rename to Extra2D/src/graphics/shader/shader_hot_reloader.cpp index 867ad84..1afd919 100644 --- a/Extra2D/src/graphics/shader_hot_reloader.cpp +++ b/Extra2D/src/graphics/shader/shader_hot_reloader.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Extra2D/src/graphics/shader_loader.cpp b/Extra2D/src/graphics/shader/shader_loader.cpp similarity index 99% rename from Extra2D/src/graphics/shader_loader.cpp rename to Extra2D/src/graphics/shader/shader_loader.cpp index 6444b59..43c3599 100644 --- a/Extra2D/src/graphics/shader_loader.cpp +++ b/Extra2D/src/graphics/shader/shader_loader.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Extra2D/src/graphics/shader_manager.cpp b/Extra2D/src/graphics/shader/shader_manager.cpp similarity index 99% rename from Extra2D/src/graphics/shader_manager.cpp rename to Extra2D/src/graphics/shader/shader_manager.cpp index b15552d..bd1b487 100644 --- a/Extra2D/src/graphics/shader_manager.cpp +++ b/Extra2D/src/graphics/shader/shader_manager.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace extra2d { diff --git a/Extra2D/src/graphics/shader_preset.cpp b/Extra2D/src/graphics/shader/shader_preset.cpp similarity index 98% rename from Extra2D/src/graphics/shader_preset.cpp rename to Extra2D/src/graphics/shader/shader_preset.cpp index 5c590ab..8f3d227 100644 --- a/Extra2D/src/graphics/shader_preset.cpp +++ b/Extra2D/src/graphics/shader/shader_preset.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include namespace extra2d { diff --git a/Extra2D/src/graphics/alpha_mask.cpp b/Extra2D/src/graphics/texture/alpha_mask.cpp similarity index 98% rename from Extra2D/src/graphics/alpha_mask.cpp rename to Extra2D/src/graphics/texture/alpha_mask.cpp index 2791653..bedb0c8 100644 --- a/Extra2D/src/graphics/alpha_mask.cpp +++ b/Extra2D/src/graphics/texture/alpha_mask.cpp @@ -1,4 +1,4 @@ -#include +#include namespace extra2d { diff --git a/Extra2D/src/graphics/texture_atlas.cpp b/Extra2D/src/graphics/texture/texture_atlas.cpp similarity index 99% rename from Extra2D/src/graphics/texture_atlas.cpp rename to Extra2D/src/graphics/texture/texture_atlas.cpp index 0c47469..5348c05 100644 --- a/Extra2D/src/graphics/texture_atlas.cpp +++ b/Extra2D/src/graphics/texture/texture_atlas.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Extra2D/src/graphics/texture_pool.cpp b/Extra2D/src/graphics/texture/texture_pool.cpp similarity index 99% rename from Extra2D/src/graphics/texture_pool.cpp rename to Extra2D/src/graphics/texture/texture_pool.cpp index f5eb4dc..841ad76 100644 --- a/Extra2D/src/graphics/texture_pool.cpp +++ b/Extra2D/src/graphics/texture/texture_pool.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include diff --git a/Extra2D/src/platform/platform_module.cpp b/Extra2D/src/platform/backend_factory.cpp similarity index 96% rename from Extra2D/src/platform/platform_module.cpp rename to Extra2D/src/platform/backend_factory.cpp index 93a704c..9759d9d 100644 --- a/Extra2D/src/platform/platform_module.cpp +++ b/Extra2D/src/platform/backend_factory.cpp @@ -1,4 +1,4 @@ -#include +#include namespace extra2d { diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp b/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp index 3e82a54..483aecf 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp +++ b/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp @@ -1,6 +1,6 @@ #include "sdl2_window.h" #include "sdl2_input.h" -#include +#include namespace extra2d { diff --git a/Extra2D/src/platform/input_module.cpp b/Extra2D/src/platform/input_module.cpp index 6babecc..db46bf1 100644 --- a/Extra2D/src/platform/input_module.cpp +++ b/Extra2D/src/platform/input_module.cpp @@ -1,213 +1,49 @@ #include -#include #include -#include +#include #include -#include -#include - -#include "backends/sdl2/sdl2_input.h" - -using json = nlohmann::json; +#include namespace extra2d { -static ModuleId s_inputModuleId = INVALID_MODULE_ID; +InputModule::InputModule(const Cfg& cfg) : cfg_(cfg) {} -ModuleId get_input_module_id() { - return s_inputModuleId; -} - -bool InputModuleConfig::validate() const { - return inputConfig.isDeadzoneValid(); -} - -void InputModuleConfig::applyPlatformConstraints(PlatformType platform) { -#ifdef __SWITCH__ - (void)platform; - inputConfig.enableVibration = true; - inputConfig.maxGamepads = 2; -#else - (void)platform; -#endif -} - -bool InputModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("enabled")) { - inputConfig.enabled = j["enabled"].get(); - } - if (j.contains("rawMouseInput")) { - inputConfig.rawMouseInput = j["rawMouseInput"].get(); - } - if (j.contains("mouseSensitivity")) { - inputConfig.mouseSensitivity = j["mouseSensitivity"].get(); - } - if (j.contains("invertMouseY")) { - inputConfig.invertMouseY = j["invertMouseY"].get(); - } - if (j.contains("invertMouseX")) { - inputConfig.invertMouseX = j["invertMouseX"].get(); - } - if (j.contains("deadzone")) { - inputConfig.deadzone = j["deadzone"].get(); - } - if (j.contains("triggerThreshold")) { - inputConfig.triggerThreshold = j["triggerThreshold"].get(); - } - if (j.contains("enableVibration")) { - inputConfig.enableVibration = j["enableVibration"].get(); - } - if (j.contains("maxGamepads")) { - inputConfig.maxGamepads = j["maxGamepads"].get(); - } - if (j.contains("autoConnectGamepads")) { - inputConfig.autoConnectGamepads = j["autoConnectGamepads"].get(); - } - if (j.contains("gamepadMappingFile")) { - inputConfig.gamepadMappingFile = j["gamepadMappingFile"].get(); - } - - return true; - } catch (...) { - return false; - } -} - -bool InputModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - - j["enabled"] = inputConfig.enabled; - j["rawMouseInput"] = inputConfig.rawMouseInput; - j["mouseSensitivity"] = inputConfig.mouseSensitivity; - j["invertMouseY"] = inputConfig.invertMouseY; - j["invertMouseX"] = inputConfig.invertMouseX; - j["deadzone"] = inputConfig.deadzone; - j["triggerThreshold"] = inputConfig.triggerThreshold; - j["enableVibration"] = inputConfig.enableVibration; - j["maxGamepads"] = inputConfig.maxGamepads; - j["autoConnectGamepads"] = inputConfig.autoConnectGamepads; - j["gamepadMappingFile"] = inputConfig.gamepadMappingFile; - - return true; - } catch (...) { - return false; - } -} - -InputModuleInitializer::InputModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , input_(nullptr) - , initialized_(false) { -} - -InputModuleInitializer::~InputModuleInitializer() { +InputModule::~InputModule() { if (initialized_) { shutdown(); } } -std::vector InputModuleInitializer::getDependencies() const { - return { get_window_module_id() }; -} - -bool InputModuleInitializer::initialize(const IModuleConfig* config) { +bool InputModule::init() { if (initialized_) return true; - const InputModuleConfig* inputConfig = dynamic_cast(config); - if (!inputConfig) { - E2D_LOG_ERROR("Invalid input module config"); + // 获取WindowModule依赖 + auto* winMod = Registry::instance().get(); + if (!winMod || !winMod->win()) { return false; } - config_ = inputConfig->inputConfig; - - auto& registry = ModuleRegistry::instance(); - auto* windowInitializer = registry.getInitializer(get_window_module_id()); - if (!windowInitializer) { - E2D_LOG_ERROR("Window module not found - Input module depends on it"); - return false; - } - - auto* windowModule = static_cast(windowInitializer); - IWindow* window = windowModule->getWindow(); - if (!window) { - E2D_LOG_ERROR("Window not created - cannot get input interface"); - return false; - } - - input_ = window->input(); + // 获取输入接口 + input_ = winMod->win()->input(); if (!input_) { - E2D_LOG_ERROR("Input interface not available from window"); return false; } - SDL2Input* sdl2Input = dynamic_cast(input_); - if (sdl2Input) { - auto eventService = ServiceLocator::instance().getService(); - if (eventService) { - sdl2Input->setEventCallback([eventService](const Event& event) { - Event mutableEvent = event; - eventService->dispatch(mutableEvent); - }); - E2D_LOG_INFO("Input events connected to EventService"); - } else { - E2D_LOG_WARN("EventService not available - input events will not be dispatched"); - } - } - initialized_ = true; - E2D_LOG_INFO("Input module initialized"); - E2D_LOG_INFO(" Deadzone: {}", config_.deadzone); - E2D_LOG_INFO(" Mouse sensitivity: {}", config_.mouseSensitivity); - E2D_LOG_INFO(" Vibration: {}", config_.enableVibration ? "enabled" : "disabled"); - return true; } -void InputModuleInitializer::shutdown() { +void InputModule::shutdown() { if (!initialized_) return; - E2D_LOG_INFO("Input module shutting down"); - input_ = nullptr; initialized_ = false; } -void InputModuleInitializer::update() { - if (!initialized_ || !input_) return; - - input_->update(); +void InputModule::update() { + if (initialized_ && input_) { + input_->update(); + } } -void register_input_module() { - if (s_inputModuleId != INVALID_MODULE_ID) return; - - s_inputModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_inputModuleId); - return initializer; - } - ); -} - -namespace { - struct InputModuleAutoRegister { - InputModuleAutoRegister() { - register_input_module(); - } - }; - - static InputModuleAutoRegister s_autoRegister; -} - -} +} // namespace extra2d diff --git a/Extra2D/src/platform/platform_init_module.cpp b/Extra2D/src/platform/platform_init_module.cpp deleted file mode 100644 index 08efe8d..0000000 --- a/Extra2D/src/platform/platform_init_module.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include -#include -#include - -#ifdef __SWITCH__ -#include -#endif - -using json = nlohmann::json; - -namespace extra2d { - -static ModuleId s_platformModuleId = INVALID_MODULE_ID; - -ModuleId get_platform_module_id() { - return s_platformModuleId; -} - -bool PlatformModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("targetPlatform")) { - int platform = j["targetPlatform"].get(); - if (platform >= 0 && platform <= 5) { - targetPlatform = static_cast(platform); - } - } - - return true; - } catch (...) { - return false; - } -} - -bool PlatformModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - j["targetPlatform"] = static_cast(targetPlatform); - return true; - } catch (...) { - return false; - } -} - -PlatformModuleInitializer::PlatformModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , initialized_(false) - , targetPlatform_(PlatformType::Auto) - , resolvedPlatform_(PlatformType::Windows) { -} - -PlatformModuleInitializer::~PlatformModuleInitializer() { - if (initialized_) { - shutdown(); - } -} - -bool PlatformModuleInitializer::initialize(const IModuleConfig* config) { - if (initialized_) return true; - - const PlatformModuleConfig* platformConfig = dynamic_cast(config); - if (platformConfig) { - targetPlatform_ = platformConfig->targetPlatform; - } - - resolvedPlatform_ = targetPlatform_; - if (resolvedPlatform_ == PlatformType::Auto) { -#ifdef __SWITCH__ - resolvedPlatform_ = PlatformType::Switch; -#else -#ifdef _WIN32 - resolvedPlatform_ = PlatformType::Windows; -#elif defined(__linux__) - resolvedPlatform_ = PlatformType::Linux; -#elif defined(__APPLE__) - resolvedPlatform_ = PlatformType::macOS; -#else - resolvedPlatform_ = PlatformType::Windows; -#endif -#endif - } - - platformConfig_ = createPlatformConfig(resolvedPlatform_); - if (!platformConfig_) { - E2D_LOG_ERROR("Failed to create platform config"); - return false; - } - - if (resolvedPlatform_ == PlatformType::Switch) { - if (!initSwitch()) { - return false; - } - } - - initialized_ = true; - E2D_LOG_INFO("Platform module initialized ({})", getPlatformTypeName(resolvedPlatform_)); - return true; -} - -bool PlatformModuleInitializer::initSwitch() { -#ifdef __SWITCH__ - Result rc; - rc = romfsInit(); - if (R_SUCCEEDED(rc)) { - E2D_LOG_INFO("RomFS initialized successfully"); - } else { - E2D_LOG_WARN("romfsInit failed: {:#08X}, will use regular filesystem", rc); - } - - rc = socketInitializeDefault(); - if (R_FAILED(rc)) { - E2D_LOG_WARN("socketInitializeDefault failed, nxlink will not be available"); - } -#endif - return true; -} - -void PlatformModuleInitializer::shutdown() { - if (!initialized_) return; - - E2D_LOG_INFO("Platform module shutting down"); - - if (resolvedPlatform_ == PlatformType::Switch) { - shutdownSwitch(); - } - - platformConfig_.reset(); - initialized_ = false; -} - -void PlatformModuleInitializer::shutdownSwitch() { -#ifdef __SWITCH__ - romfsExit(); - socketExit(); -#endif -} - -void register_platform_module() { - if (s_platformModuleId != INVALID_MODULE_ID) return; - - s_platformModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_platformModuleId); - return initializer; - } - ); -} - -namespace { - struct PlatformModuleAutoRegister { - PlatformModuleAutoRegister() { - register_platform_module(); - } - }; - - static PlatformModuleAutoRegister s_autoRegister; -} - -} // namespace extra2d diff --git a/Extra2D/src/platform/window_module.cpp b/Extra2D/src/platform/window_module.cpp index 82b3400..02767dc 100644 --- a/Extra2D/src/platform/window_module.cpp +++ b/Extra2D/src/platform/window_module.cpp @@ -1,258 +1,92 @@ #include -#include -#include +#include +#include #include -#include #include #ifdef __SWITCH__ #include #endif -using json = nlohmann::json; - namespace extra2d { -static ModuleId s_windowModuleId = INVALID_MODULE_ID; +// 前向声明 SDL2 后端初始化函数 +void initSDL2Backend(); -ModuleId get_window_module_id() { - return s_windowModuleId; -} +WindowModule::WindowModule(const Cfg& cfg) : cfg_(cfg) {} -void WindowModuleConfig::applyPlatformConstraints(PlatformType platform) { -#ifdef __SWITCH__ - (void)platform; - windowConfig.mode = WindowMode::Fullscreen; - windowConfig.resizable = false; - windowConfig.highDPI = false; - windowConfig.width = 1920; - windowConfig.height = 1080; -#else - (void)platform; -#endif -} - -bool WindowModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("title")) { - windowConfig.title = j["title"].get(); - } - if (j.contains("width")) { - windowConfig.width = j["width"].get(); - } - if (j.contains("height")) { - windowConfig.height = j["height"].get(); - } - if (j.contains("minWidth")) { - windowConfig.minWidth = j["minWidth"].get(); - } - if (j.contains("minHeight")) { - windowConfig.minHeight = j["minHeight"].get(); - } - if (j.contains("fullscreen")) { - windowConfig.mode = j["fullscreen"].get() ? WindowMode::Fullscreen : WindowMode::Windowed; - } - if (j.contains("mode")) { - std::string modeStr = j["mode"].get(); - if (modeStr == "fullscreen") { - windowConfig.mode = WindowMode::Fullscreen; - } else if (modeStr == "borderless") { - windowConfig.mode = WindowMode::Borderless; - } else { - windowConfig.mode = WindowMode::Windowed; - } - } - if (j.contains("vsync")) { - windowConfig.vsync = j["vsync"].get(); - } - if (j.contains("resizable")) { - windowConfig.resizable = j["resizable"].get(); - } - if (j.contains("highDPI")) { - windowConfig.highDPI = j["highDPI"].get(); - } - if (j.contains("multisamples")) { - windowConfig.multisamples = j["multisamples"].get(); - } - - return true; - } catch (...) { - return false; - } -} - -bool WindowModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - j["title"] = windowConfig.title; - j["width"] = windowConfig.width; - j["height"] = windowConfig.height; - j["minWidth"] = windowConfig.minWidth; - j["minHeight"] = windowConfig.minHeight; - - switch (windowConfig.mode) { - case WindowMode::Fullscreen: - j["mode"] = "fullscreen"; - break; - case WindowMode::Borderless: - j["mode"] = "borderless"; - break; - default: - j["mode"] = "windowed"; - break; - } - - j["vsync"] = windowConfig.vsync; - j["resizable"] = windowConfig.resizable; - j["highDPI"] = windowConfig.highDPI; - j["multisamples"] = windowConfig.multisamples; - return true; - } catch (...) { - return false; - } -} - -WindowModuleInitializer::WindowModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , initialized_(false) - , sdl2Initialized_(false) { -} - -WindowModuleInitializer::~WindowModuleInitializer() { +WindowModule::~WindowModule() { if (initialized_) { shutdown(); } } -bool WindowModuleInitializer::initSDL2() { - Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER; - -#ifdef __SWITCH__ - initFlags |= SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER; -#endif - - if (SDL_Init(initFlags) != 0) { - E2D_LOG_ERROR("Failed to initialize SDL2: {}", SDL_GetError()); - return false; - } - - sdl2Initialized_ = true; - E2D_LOG_INFO("SDL2 initialized successfully"); - return true; -} - -void WindowModuleInitializer::shutdownSDL2() { - if (!sdl2Initialized_) return; - - SDL_Quit(); - sdl2Initialized_ = false; - E2D_LOG_INFO("SDL2 shutdown"); -} - -bool WindowModuleInitializer::initialize(const IModuleConfig* config) { +bool WindowModule::init() { if (initialized_) return true; - - const WindowModuleConfig* windowConfig = dynamic_cast(config); - if (!windowConfig) { - E2D_LOG_ERROR("Invalid window module config"); - return false; - } - - windowConfig_ = windowConfig->windowConfig; #ifdef __SWITCH__ - windowConfig_.mode = WindowMode::Fullscreen; - windowConfig_.resizable = false; - windowConfig_.highDPI = false; - E2D_LOG_INFO("Switch platform: forcing fullscreen mode"); + cfg_.mode = WindowMode::Fullscreen; #endif - if (!initSDL2()) { - return false; - } - - extern void initSDL2Backend(); + // 初始化SDL后端(注册到工厂) initSDL2Backend(); - if (!BackendFactory::has("sdl2")) { - E2D_LOG_ERROR("SDL2 backend not registered!"); - shutdownSDL2(); + // 初始化SDL + Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER; +#ifdef __SWITCH__ + flags |= SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER; +#endif + + if (SDL_Init(flags) != 0) { + E2D_LOG_ERROR("SDL_Init failed: {}", SDL_GetError()); + return false; + } + sdlInited_ = true; + E2D_LOG_INFO("SDL initialized successfully"); + + // 创建窗口配置 + WindowConfigData winCfg; + winCfg.title = cfg_.title; + winCfg.width = cfg_.w; + winCfg.height = cfg_.h; + winCfg.mode = cfg_.mode; + winCfg.vsync = cfg_.vsync; + + E2D_LOG_INFO("Creating window with size {}x{}", cfg_.w, cfg_.h); + + // 创建窗口(使用配置的后端) + win_ = BackendFactory::createWindow(cfg_.backend); + if (!win_) { + E2D_LOG_ERROR("Failed to create window backend"); + shutdown(); return false; } - if (!createWindow(windowConfig_)) { + if (!win_->create(winCfg)) { E2D_LOG_ERROR("Failed to create window"); - shutdownSDL2(); + shutdown(); return false; } + E2D_LOG_INFO("Window created successfully"); initialized_ = true; - E2D_LOG_INFO("Window module initialized"); - E2D_LOG_INFO(" Window: {}x{}", window_->width(), window_->height()); - E2D_LOG_INFO(" Backend: SDL2"); - E2D_LOG_INFO(" VSync: {}", windowConfig_.vsync); - E2D_LOG_INFO(" Fullscreen: {}", windowConfig_.isFullscreen()); - return true; } -bool WindowModuleInitializer::createWindow(const WindowConfigData& config) { - window_ = BackendFactory::createWindow("sdl2"); - if (!window_) { - E2D_LOG_ERROR("Failed to create SDL2 window"); - return false; - } - - if (!window_->create(config)) { - E2D_LOG_ERROR("Failed to create window with specified config"); - return false; - } - - return true; -} - -void WindowModuleInitializer::shutdown() { +void WindowModule::shutdown() { if (!initialized_) return; - E2D_LOG_INFO("Window module shutting down"); - - if (window_) { - window_->destroy(); - window_.reset(); + if (win_) { + win_->destroy(); + win_.reset(); } - shutdownSDL2(); + if (sdlInited_) { + SDL_Quit(); + sdlInited_ = false; + } initialized_ = false; } -void register_window_module() { - if (s_windowModuleId != INVALID_MODULE_ID) return; - - s_windowModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_windowModuleId); - return initializer; - } - ); -} - -namespace { - struct WindowModuleAutoRegister { - WindowModuleAutoRegister() { - register_window_module(); - } - }; - - static WindowModuleAutoRegister s_autoRegister; -} - -} +} // namespace extra2d diff --git a/Extra2D/src/resource/resource_config.cpp b/Extra2D/src/resource/resource_config.cpp deleted file mode 100644 index 2631b5a..0000000 --- a/Extra2D/src/resource/resource_config.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -namespace extra2d { - -void ResourceConfigData::addSearchPath(const std::string& path) { - if (!hasSearchPath(path)) { - searchPaths.push_back(path); - } -} - -void ResourceConfigData::removeSearchPath(const std::string& path) { - auto it = std::find(searchPaths.begin(), searchPaths.end(), path); - if (it != searchPaths.end()) { - searchPaths.erase(it); - } -} - -bool ResourceConfigData::hasSearchPath(const std::string& path) const { - return std::find(searchPaths.begin(), searchPaths.end(), path) != searchPaths.end(); -} - -} diff --git a/Extra2D/src/scene/node.cpp b/Extra2D/src/scene/node.cpp index 2e5b06f..94752cf 100644 --- a/Extra2D/src/scene/node.cpp +++ b/Extra2D/src/scene/node.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/Extra2D/src/scene/scene.cpp b/Extra2D/src/scene/scene.cpp index 05670c4..126eb6e 100644 --- a/Extra2D/src/scene/scene.cpp +++ b/Extra2D/src/scene/scene.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include diff --git a/Extra2D/src/scene/scene_manager.cpp b/Extra2D/src/scene/scene_manager.cpp index 7a9387a..a7dab1b 100644 --- a/Extra2D/src/scene/scene_manager.cpp +++ b/Extra2D/src/scene/scene_manager.cpp @@ -1,7 +1,7 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -545,7 +545,8 @@ bool SceneManager::hasScene(const std::string &name) const { * 更新当前场景并分发指针事件 */ void SceneManager::update(float dt) { - if (isTransitioning_) { + if (isTransitioning_ && activeTransitionScene_) { + activeTransitionScene_->updateTransition(dt); hoverTarget_ = nullptr; captureTarget_ = nullptr; hasLastPointerWorld_ = false; @@ -746,8 +747,9 @@ void SceneManager::finishTransition() { * 处理鼠标悬停、移动、点击和滚轮事件 */ void SceneManager::dispatchPointerEvents(Scene &scene) { - auto &input = Application::get().input(); - Vec2 screenPos = input.mouse(); + auto *input = Application::get().input(); + if (!input) return; + Vec2 screenPos = input->mouse(); Vec2 worldPos = screenPos; if (auto *camera = scene.getActiveCamera()) { @@ -784,13 +786,13 @@ void SceneManager::dispatchPointerEvents(Scene &scene) { dispatchToNode(hoverTarget_, evt); } - float scrollDelta = input.scrollDelta(); + float scrollDelta = input->scrollDelta(); if (hoverTarget_ && scrollDelta != 0.0f) { Event evt = Event::createMouseScroll(Vec2(0.0f, scrollDelta), worldPos); dispatchToNode(hoverTarget_, evt); } - if (input.pressed(Mouse::Left)) { + if (input->pressed(Mouse::Left)) { captureTarget_ = hoverTarget_; if (captureTarget_) { Event evt = Event::createMouseButtonPress(static_cast(Mouse::Left), @@ -804,7 +806,7 @@ void SceneManager::dispatchPointerEvents(Scene &scene) { } } - if (input.released(Mouse::Left)) { + if (input->released(Mouse::Left)) { Node *target = captureTarget_ ? captureTarget_ : hoverTarget_; if (target) { Event evt = Event::createMouseButtonRelease(static_cast(Mouse::Left), diff --git a/Extra2D/src/scene/shape_node.cpp b/Extra2D/src/scene/shape_node.cpp index 95c8a88..676bc78 100644 --- a/Extra2D/src/scene/shape_node.cpp +++ b/Extra2D/src/scene/shape_node.cpp @@ -1,7 +1,7 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/Extra2D/src/scene/sprite.cpp b/Extra2D/src/scene/sprite.cpp index d5368c4..eae5658 100644 --- a/Extra2D/src/scene/sprite.cpp +++ b/Extra2D/src/scene/sprite.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include -#include +#include +#include +#include #include namespace extra2d { diff --git a/Extra2D/src/scene/transition_box_scene.cpp b/Extra2D/src/scene/transition_box_scene.cpp index 00ca3c3..e4e0fe0 100644 --- a/Extra2D/src/scene/transition_box_scene.cpp +++ b/Extra2D/src/scene/transition_box_scene.cpp @@ -1,7 +1,8 @@ #include #include #include -#include +#include +#include #include #include @@ -38,6 +39,14 @@ Ptr TransitionBoxScene::create(float duration, void TransitionBoxScene::onTransitionStart() { } +/** + * @brief 更新过渡进度 + * @param dt 帧间隔时间(秒) + */ +void TransitionBoxScene::updateTransition(float dt) { + TransitionScene::updateTransition(dt); +} + /** * @brief 渲染过渡内容 * @param renderer 渲染后端引用 @@ -46,11 +55,8 @@ void TransitionBoxScene::onTransitionStart() { */ void TransitionBoxScene::renderContent(RenderBackend &renderer) { auto &app = Application::get(); - float windowWidth = static_cast(app.window().width()); - float windowHeight = static_cast(app.window().height()); - - elapsed_ += 1.0f / 60.0f; - progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f; + float windowWidth = static_cast(app.window()->width()); + float windowHeight = static_cast(app.window()->height()); if (inScene_) { inScene_->renderContent(renderer); @@ -78,10 +84,6 @@ void TransitionBoxScene::renderContent(RenderBackend &renderer) { renderer.fillRect(Rect(x * cellW, y * cellH, cellW + 1.0f, cellH + 1.0f), Colors::Black); } - - if (progress_ >= 1.0f && !isFinished_) { - finish(); - } } } // namespace extra2d diff --git a/Extra2D/src/scene/transition_fade_scene.cpp b/Extra2D/src/scene/transition_fade_scene.cpp index 31a9b7c..9767dbb 100644 --- a/Extra2D/src/scene/transition_fade_scene.cpp +++ b/Extra2D/src/scene/transition_fade_scene.cpp @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include #include #include @@ -39,30 +40,29 @@ void TransitionFadeScene::onTransitionStart() { E2D_LOG_DEBUG("TransitionFadeScene::onTransitionStart - 启动淡入淡出过渡"); } -/** - * @brief 渲染过渡内容 - * @param renderer 渲染后端引用 - * - * 根据进度渲染新旧场景,并绘制遮罩层 - */ -void TransitionFadeScene::renderContent(RenderBackend &renderer) { - auto &app = Application::get(); - float windowWidth = static_cast(app.window().width()); - float windowHeight = static_cast(app.window().height()); - - elapsed_ += 1.0f / 60.0f; - progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f; +void TransitionFadeScene::updateTransition(float dt) { + // 调用基类更新进度 + TransitionScene::updateTransition(dt); + // 检查是否需要切换场景显示 if (!hasSwitched_ && progress_ >= 0.5f) { hideOutShowIn(); } +} +void TransitionFadeScene::renderContent(RenderBackend &renderer) { + auto &app = Application::get(); + float windowWidth = static_cast(app.window()->width()); + float windowHeight = static_cast(app.window()->height()); + + // 根据进度选择渲染哪个场景 if (progress_ < 0.5f) { drawOutScene(renderer); } else { drawInScene(renderer); } + // 计算遮罩透明度 float maskAlpha; if (progress_ < 0.5f) { maskAlpha = progress_ * 2.0f; @@ -80,10 +80,6 @@ void TransitionFadeScene::renderContent(RenderBackend &renderer) { Color maskColor = maskColor_; maskColor.a = maskAlpha; renderer.fillRect(Rect(0.0f, 0.0f, windowWidth, windowHeight), maskColor); - - if (progress_ >= 1.0f && !isFinished_) { - finish(); - } } /** diff --git a/Extra2D/src/scene/transition_flip_scene.cpp b/Extra2D/src/scene/transition_flip_scene.cpp index 4d5c077..7b0119a 100644 --- a/Extra2D/src/scene/transition_flip_scene.cpp +++ b/Extra2D/src/scene/transition_flip_scene.cpp @@ -1,7 +1,7 @@ #include #include -#include -#include +#include +#include namespace extra2d { @@ -36,6 +36,14 @@ Ptr TransitionFlipScene::create(float duration, void TransitionFlipScene::onTransitionStart() { } +/** + * @brief 更新过渡进度 + * @param dt 帧间隔时间(秒) + */ +void TransitionFlipScene::updateTransition(float dt) { + TransitionScene::updateTransition(dt); +} + /** * @brief 渲染过渡内容 * @param renderer 渲染后端引用 @@ -43,9 +51,6 @@ void TransitionFlipScene::onTransitionStart() { * 根据进度控制新旧场景的翻转角度 */ void TransitionFlipScene::renderContent(RenderBackend &renderer) { - elapsed_ += 1.0f / 60.0f; - progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f; - float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ : -1.0f + (4.0f - 2.0f * progress_) * progress_; @@ -99,9 +104,6 @@ void TransitionFlipScene::renderContent(RenderBackend &renderer) { } } - if (progress_ >= 1.0f && !isFinished_) { - finish(); - } } } // namespace extra2d diff --git a/Extra2D/src/scene/transition_scale_scene.cpp b/Extra2D/src/scene/transition_scale_scene.cpp index 663345f..7ca6de6 100644 --- a/Extra2D/src/scene/transition_scale_scene.cpp +++ b/Extra2D/src/scene/transition_scale_scene.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include namespace extra2d { @@ -32,6 +32,14 @@ Ptr TransitionScaleScene::create(float duration, void TransitionScaleScene::onTransitionStart() { } +/** + * @brief 更新过渡进度 + * @param dt 帧间隔时间(秒) + */ +void TransitionScaleScene::updateTransition(float dt) { + TransitionScene::updateTransition(dt); +} + /** * @brief 渲染过渡内容 * @param renderer 渲染后端引用 @@ -39,9 +47,6 @@ void TransitionScaleScene::onTransitionStart() { * 根据进度控制新旧场景的缩放比例 */ void TransitionScaleScene::renderContent(RenderBackend &renderer) { - elapsed_ += 1.0f / 60.0f; - progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f; - float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ : -1.0f + (4.0f - 2.0f * progress_) * progress_; @@ -79,9 +84,6 @@ void TransitionScaleScene::renderContent(RenderBackend &renderer) { } } - if (progress_ >= 1.0f && !isFinished_) { - finish(); - } } } // namespace extra2d diff --git a/Extra2D/src/scene/transition_scene.cpp b/Extra2D/src/scene/transition_scene.cpp index f512e9e..c6975ea 100644 --- a/Extra2D/src/scene/transition_scene.cpp +++ b/Extra2D/src/scene/transition_scene.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace extra2d { @@ -50,13 +50,32 @@ void TransitionScene::onExit() { Scene::onExit(); } +/** + * @brief 更新过渡进度(基类默认实现) + * @param dt 帧间隔时间(秒) + * + * 子类应重写此方法更新动画进度,默认实现简单计时 + */ +void TransitionScene::updateTransition(float dt) { + if (isFinished_ || isCancelled_) { + return; + } + + elapsed_ += dt; + progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f; + + if (progress_ >= 1.0f) { + finish(); + } +} + /** * @brief 完成过渡 * * 标记过渡完成并调用完成回调 */ void TransitionScene::finish() { - if (isFinished_) { + if (isFinished_ || isCancelled_) { return; } @@ -69,6 +88,30 @@ void TransitionScene::finish() { } } +/** + * @brief 取消过渡 + * @param immediate 是否立即完成(false则回滚到原场景) + */ +void TransitionScene::cancel(bool immediate) { + if (isFinished_ || isCancelled_) { + return; + } + + isCancelled_ = true; + + if (immediate) { + // 立即完成,切换到新场景 + E2D_LOG_DEBUG("TransitionScene::cancel - 立即完成过渡"); + finish(); + } else { + // 回滚到原场景 + E2D_LOG_DEBUG("TransitionScene::cancel - 取消过渡,回滚到原场景"); + if (cancelCallback_) { + cancelCallback_(); + } + } +} + /** * @brief 渲染过渡内容 * @param renderer 渲染后端引用 diff --git a/Extra2D/src/scene/transition_slide_scene.cpp b/Extra2D/src/scene/transition_slide_scene.cpp index 9ab1a85..85d7f0b 100644 --- a/Extra2D/src/scene/transition_slide_scene.cpp +++ b/Extra2D/src/scene/transition_slide_scene.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include namespace extra2d { @@ -35,6 +35,14 @@ Ptr TransitionSlideScene::create( void TransitionSlideScene::onTransitionStart() { } +/** + * @brief 更新过渡进度 + * @param dt 帧间隔时间(秒) + */ +void TransitionSlideScene::updateTransition(float dt) { + TransitionScene::updateTransition(dt); +} + /** * @brief 渲染过渡内容 * @param renderer 渲染后端引用 @@ -59,9 +67,6 @@ void TransitionSlideScene::renderContent(RenderBackend &renderer) { } } - elapsed_ += 1.0f / 60.0f; - progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f; - float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ : -1.0f + (4.0f - 2.0f * progress_) * progress_; @@ -131,9 +136,6 @@ void TransitionSlideScene::renderContent(RenderBackend &renderer) { } } - if (progress_ >= 1.0f && !isFinished_) { - finish(); - } } } // namespace extra2d diff --git a/Extra2D/src/services/logger_service.cpp b/Extra2D/src/services/logger_service.cpp new file mode 100644 index 0000000..8305dd7 --- /dev/null +++ b/Extra2D/src/services/logger_service.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +// ConsoleLogger 实现 +class ConsoleLogger::Impl { +public: + std::mutex mutex_; +}; + +ConsoleLogger::ConsoleLogger() : level_(LogLevel::Info), impl_(std::make_unique()) { + info_.name = "ConsoleLogger"; + info_.priority = ServicePriority::Core; +} + +ConsoleLogger::~ConsoleLogger() = default; + +bool ConsoleLogger::initialize() { + setState(ServiceState::Running); + return true; +} + +void ConsoleLogger::shutdown() { + setState(ServiceState::Stopped); +} + +void ConsoleLogger::setLevel(LogLevel level) { + level_ = level; +} + +LogLevel ConsoleLogger::getLevel() const { + return level_; +} + +bool ConsoleLogger::isEnabled(LogLevel level) const { + return static_cast(level) >= static_cast(level_); +} + +void ConsoleLogger::log(LogLevel level, const char* fmt, ...) { + if (!isEnabled(level)) return; + + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + output(level, buffer); +} + +void ConsoleLogger::log(LogLevel level, const std::string& msg) { + if (!isEnabled(level)) return; + output(level, msg.c_str()); +} + +void ConsoleLogger::trace(const char* fmt, ...) { + if (!isEnabled(LogLevel::Trace)) return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Trace, buffer); +} + +void ConsoleLogger::debug(const char* fmt, ...) { + if (!isEnabled(LogLevel::Debug)) return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Debug, buffer); +} + +void ConsoleLogger::info(const char* fmt, ...) { + if (!isEnabled(LogLevel::Info)) return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Info, buffer); +} + +void ConsoleLogger::warn(const char* fmt, ...) { + if (!isEnabled(LogLevel::Warn)) return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Warn, buffer); +} + +void ConsoleLogger::error(const char* fmt, ...) { + if (!isEnabled(LogLevel::Error)) return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Error, buffer); +} + +void ConsoleLogger::fatal(const char* fmt, ...) { + if (!isEnabled(LogLevel::Fatal)) return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Fatal, buffer); +} + +void ConsoleLogger::output(LogLevel level, const char* msg) { + std::lock_guard lock(impl_->mutex_); + + auto now = std::chrono::system_clock::now(); + auto time = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast( + now.time_since_epoch()) % 1000; + + std::tm tm; +#ifdef _WIN32 + localtime_s(&tm, &time); +#else + localtime_r(&time, &tm); +#endif + + const char* levelStr = getLevelString(level); + + // 颜色代码 + const char* color = ""; + const char* reset = "\033[0m"; + + switch (level) { + case LogLevel::Trace: color = "\033[90m"; break; + case LogLevel::Debug: color = "\033[36m"; break; + case LogLevel::Info: color = "\033[32m"; break; + case LogLevel::Warn: color = "\033[33m"; break; + case LogLevel::Error: color = "\033[31m"; break; + case LogLevel::Fatal: color = "\033[35m"; break; + default: break; + } + + printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", + color, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)ms.count(), + levelStr, msg, reset); +} + +const char* ConsoleLogger::getLevelString(LogLevel level) { + switch (level) { + case LogLevel::Trace: return "TRACE"; + case LogLevel::Debug: return "DEBUG"; + case LogLevel::Info: return "INFO"; + case LogLevel::Warn: return "WARN"; + case LogLevel::Error: return "ERROR"; + case LogLevel::Fatal: return "FATAL"; + default: return "UNKNOWN"; + } +} + +} // namespace extra2d diff --git a/Extra2D/src/utils/logger.cpp b/Extra2D/src/utils/logger.cpp deleted file mode 100644 index f1ebdf9..0000000 --- a/Extra2D/src/utils/logger.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef __SWITCH__ -#include -#endif - -namespace extra2d { - -LogLevel Logger::level_ = LogLevel::Info; -bool Logger::initialized_ = false; -bool Logger::consoleOutput_ = true; -bool Logger::fileOutput_ = false; -std::string Logger::logFile_; -void *Logger::logFileHandle_ = nullptr; - -const char *Logger::getLevelString(LogLevel level) { - switch (level) { - case LogLevel::Trace: - return "TRACE"; - case LogLevel::Debug: - return "DEBUG"; - case LogLevel::Info: - return "INFO "; - case LogLevel::Warn: - return "WARN "; - case LogLevel::Error: - return "ERROR"; - case LogLevel::Fatal: - return "FATAL"; - default: - return "UNKNOWN"; - } -} - -void Logger::writeToConsole(LogLevel level, const char *msg) { - const char *levelStr = getLevelString(level); - -#ifdef _WIN32 - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - WORD color = 7; - switch (level) { - case LogLevel::Trace: color = 8; break; - case LogLevel::Debug: color = 8; break; - case LogLevel::Info: color = 7; break; - case LogLevel::Warn: color = 14; break; - case LogLevel::Error: color = 12; break; - case LogLevel::Fatal: color = 12 | FOREGROUND_INTENSITY; break; - default: break; - } - SetConsoleTextAttribute(hConsole, color); - printf("[%s] %s\n", levelStr, msg); - SetConsoleTextAttribute(hConsole, 7); -#else - const char *colorCode = "\033[0m"; - switch (level) { - case LogLevel::Trace: colorCode = "\033[90m"; break; - case LogLevel::Debug: colorCode = "\033[90m"; break; - case LogLevel::Info: colorCode = "\033[0m"; break; - case LogLevel::Warn: colorCode = "\033[33m"; break; - case LogLevel::Error: colorCode = "\033[31m"; break; - case LogLevel::Fatal: colorCode = "\033[1;31m"; break; - default: break; - } - printf("%s[%s] %s\033[0m\n", colorCode, levelStr, msg); -#endif -} - -void Logger::writeToFile(LogLevel level, const char *msg) { - if (!logFileHandle_) return; - - FILE *fp = static_cast(logFileHandle_); - - time_t now = time(nullptr); - struct tm *tm_info = localtime(&now); - char timeBuf[32]; - strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", tm_info); - - fprintf(fp, "[%s] [%s] %s\n", timeBuf, getLevelString(level), msg); - fflush(fp); -} - -void Logger::outputLog(LogLevel level, const char *msg) { - if (consoleOutput_) { - writeToConsole(level, msg); - } - if (fileOutput_) { - writeToFile(level, msg); - } -} - -void Logger::init() { - if (initialized_) { - return; - } - -#ifdef _WIN32 - SetConsoleOutputCP(CP_UTF8); - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hOut != INVALID_HANDLE_VALUE) { - DWORD mode = 0; - if (GetConsoleMode(hOut, &mode)) { - mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(hOut, mode); - } - } -#endif - -#ifdef __SWITCH__ - consoleInit(NULL); -#endif - - initialized_ = true; - log(LogLevel::Info, "Logger initialized"); -} - -void Logger::shutdown() { - if (initialized_) { - log(LogLevel::Info, "Logger shutting down"); - } - - if (logFileHandle_) { - fclose(static_cast(logFileHandle_)); - logFileHandle_ = nullptr; - } - -#ifdef __SWITCH__ - consoleExit(NULL); -#endif - - initialized_ = false; - fileOutput_ = false; -} - -void Logger::setLevel(LogLevel level) { - level_ = level; -} - -void Logger::setConsoleOutput(bool enable) { - consoleOutput_ = enable; -} - -void Logger::setFileOutput(const std::string &filename) { - if (logFileHandle_) { - fclose(static_cast(logFileHandle_)); - logFileHandle_ = nullptr; - } - - logFile_ = filename; - fileOutput_ = !filename.empty(); - - if (fileOutput_) { -#ifdef _WIN32 - FILE *fp = nullptr; - fopen_s(&fp, filename.c_str(), "a"); -#else - FILE *fp = fopen(filename.c_str(), "a"); -#endif - logFileHandle_ = fp; - - if (fp) { - time_t now = time(nullptr); - struct tm *tm_info = localtime(&now); - char timeBuf[32]; - strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", tm_info); - fprintf(fp, "\n=== Log session started at %s ===\n", timeBuf); - fflush(fp); - } - } -} - -} // namespace extra2d diff --git a/Extra2D/src/utils/logger_module.cpp b/Extra2D/src/utils/logger_module.cpp deleted file mode 100644 index 01713fd..0000000 --- a/Extra2D/src/utils/logger_module.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include -#include -#include - -using json = nlohmann::json; - -namespace extra2d { - -bool LoggerModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("logLevel")) { - int level = j["logLevel"].get(); - if (level >= 0 && level <= 6) { - logLevel = static_cast(level); - } - } - - if (j.contains("consoleOutput")) { - consoleOutput = j["consoleOutput"].get(); - } - - if (j.contains("fileOutput")) { - fileOutput = j["fileOutput"].get(); - } - - if (j.contains("logFilePath")) { - logFilePath = j["logFilePath"].get(); - } - - return true; - } catch (...) { - return false; - } -} - -bool LoggerModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - j["logLevel"] = static_cast(logLevel); - j["consoleOutput"] = consoleOutput; - j["fileOutput"] = fileOutput; - j["logFilePath"] = logFilePath; - return true; - } catch (...) { - return false; - } -} - -LoggerModuleInitializer::LoggerModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , initialized_(false) { -} - -LoggerModuleInitializer::~LoggerModuleInitializer() { - if (initialized_) { - shutdown(); - } -} - -bool LoggerModuleInitializer::initialize(const IModuleConfig* config) { - if (initialized_) return true; - - const LoggerModuleConfig* loggerConfig = dynamic_cast(config); - - Logger::init(); - - if (loggerConfig) { - Logger::setLevel(loggerConfig->logLevel); - Logger::setConsoleOutput(loggerConfig->consoleOutput); - if (loggerConfig->fileOutput && !loggerConfig->logFilePath.empty()) { - Logger::setFileOutput(loggerConfig->logFilePath); - } - } - - initialized_ = true; - E2D_LOG_INFO("Logger module initialized"); - return true; -} - -void LoggerModuleInitializer::shutdown() { - if (!initialized_) return; - - E2D_LOG_INFO("Logger module shutting down"); - Logger::shutdown(); - initialized_ = false; -} - -namespace { - static ModuleId s_loggerModuleId = INVALID_MODULE_ID; - - struct LoggerModuleRegistrar { - LoggerModuleRegistrar() { - s_loggerModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_loggerModuleId); - return initializer; - } - ); - } - }; - - static LoggerModuleRegistrar s_registrar; -} - -} // namespace extra2d diff --git a/README.md b/README.md index 1777d8e..735bc41 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,58 @@ xmake run demo_basic ## 目录结构 +``` +Extra2D/ +├── Extra2D/ +│ ├── include/ +│ │ ├── KHR/ # KHR 平台头文件 +│ │ ├── extra2d/ # 引擎公共头文件 +│ │ │ ├── app/ # 应用程序 +│ │ │ ├── audio/ # 音频配置 +│ │ │ ├── config/ # 配置系统 +│ │ │ ├── core/ # 核心类型 +│ │ │ ├── event/ # 事件系统 +│ │ │ ├── graphics/ # 图形渲染 +│ │ │ │ ├── core/ # 渲染核心 +│ │ │ │ ├── camera/ # 相机和视口 +│ │ │ │ ├── shader/ # Shader 系统 +│ │ │ │ ├── texture/ # 纹理系统 +│ │ │ │ ├── memory/ # GPU 内存管理 +│ │ │ │ └── opengl/ # OpenGL 实现 +│ │ │ ├── platform/ # 平台抽象 +│ │ │ ├── scene/ # 场景系统 +│ │ │ ├── services/ # 服务接口 +│ │ │ └── utils/ # 工具库 +│ │ ├── glad/ # OpenGL 加载器 +│ │ └── stb/ # STB 单文件库 +│ ├── shaders/ # 着色器文件 +│ │ ├── builtin/ # 内置着色器 +│ │ ├── common/ # 公共着色器代码 +│ │ └── effects/ # 特效着色器 +│ └── src/ # 源文件 +│ ├── app/ # 应用实现 +│ ├── config/ # 配置实现 +│ ├── core/ # 核心实现 +│ ├── event/ # 事件实现 +│ ├── glad/ # GLAD 实现 +│ ├── graphics/ # 图形实现 +│ │ ├── core/ # 渲染核心 +│ │ ├── camera/ # 相机和视口 +│ │ ├── shader/ # Shader 系统 +│ │ ├── texture/ # 纹理系统 +│ │ ├── memory/ # GPU 内存管理 +│ │ └── opengl/ # OpenGL 实现 +│ ├── platform/ # 平台实现 +│ │ └── backends/ # 后端实现 +│ │ └── sdl2/ # SDL2 后端 +│ ├── scene/ # 场景实现 +│ ├── services/ # 服务实现 +│ └── utils/ # 工具实现 +├── docs/ # 文档 +├── examples/ # 示例程序 +│ └── basic/ # 基础示例 +└── xmake/ # 构建配置 + └── toolchains/ # 工具链配置 ``` Extra2D/ ├── Extra2D/ diff --git a/docs/module_system.md b/docs/module_system.md index ef074dc..5a0fda1 100644 --- a/docs/module_system.md +++ b/docs/module_system.md @@ -52,16 +52,36 @@ Extra2D/include/extra2d/ │ ├── module_config.h # 模块配置接口 │ └── config_manager.h # 配置管理器 ├── platform/ -│ ├── window_config.h # 窗口模块配置 -│ └── input_config.h # 输入模块配置 +│ └── window_module.h # 窗口模块(含 Cfg 配置结构) ├── graphics/ -│ └── render_config.h # 渲染模块配置 -├── audio/ -│ └── audio_config.h # 音频模块配置 -├── debug/ -│ └── debug_config.h # 调试模块配置 -└── resource/ - └── resource_config.h # 资源模块配置 +│ ├── core/ # 渲染核心 +│ │ ├── render_backend.h # 渲染后端接口 +│ │ ├── render_command.h # 渲染命令 +│ │ ├── render_module.h # 渲染模块(含 Cfg 配置结构) +│ │ └── render_target.h # 渲染目标 +│ ├── camera/ # 相机和视口 +│ │ ├── camera.h # 2D 相机 +│ │ └── viewport_adapter.h # 视口适配器 +│ ├── shader/ # Shader 系统 +│ │ ├── shader_interface.h +│ │ ├── shader_manager.h +│ │ ├── shader_loader.h +│ │ ├── shader_cache.h +│ │ ├── shader_hot_reloader.h +│ │ └── shader_preset.h +│ ├── texture/ # 纹理系统 +│ │ ├── texture.h # 纹理接口 +│ │ ├── texture_atlas.h # 纹理图集 +│ │ ├── texture_pool.h # 纹理池 +│ │ ├── alpha_mask.h # Alpha 遮罩 +│ │ └── font.h # 字体接口 +│ ├── memory/ # GPU 内存管理 +│ │ ├── vram_manager.h # VRAM 管理器 +│ │ └── gpu_context.h # GPU 上下文 +│ └── opengl/ # OpenGL 实现 +├── scene/ # 场景系统 +├── services/ # 服务接口 +└── event/ # 事件系统 ``` ### AppConfig 结构 @@ -442,12 +462,13 @@ if (caps.supportsGamepad) { **配置**: ```cpp -WindowConfigData config; -config.title = "My App"; -config.width = 1280; -config.height = 720; -config.mode = WindowMode::Windowed; -config.vsync = true; +WindowModule::Cfg cfg; +cfg.title = "My App"; +cfg.w = 1280; +cfg.h = 720; +cfg.mode = WindowMode::Windowed; +cfg.vsync = true; +cfg.backend = "sdl2"; // 可选:指定后端 ``` **平台约束**: @@ -461,10 +482,10 @@ config.vsync = true; **配置**: ```cpp -InputConfigData config; -config.deadzone = 0.15f; -config.mouseSensitivity = 1.0f; -config.enableVibration = true; +InputModule::Cfg cfg; +cfg.deadzone = 0.15f; +cfg.mouseSensitivity = 1.0f; +cfg.enableVibration = true; ``` **使用示例**: @@ -498,11 +519,11 @@ if (input->gamepad()) { **配置**: ```cpp -RenderConfigData config; -config.backend = BackendType::OpenGL; -config.vsync = true; -config.targetFPS = 60; -config.multisamples = 4; +RenderModule::Cfg cfg; +cfg.backend = BackendType::OpenGL; +cfg.vsync = true; +cfg.targetFPS = 60; +cfg.multisamples = 4; ``` --- @@ -694,14 +715,23 @@ if (caps.supportsTouch) { /* 支持触摸 */ } ```cpp // 好的做法:模块管理自己的配置 -class WindowModuleConfig : public IModuleConfig { - WindowConfigData windowConfig; // 模块内部配置 +class WindowModule : public Module { + Cfg cfg_; // 模块内部配置 +public: + struct Cfg { + std::string title = "Extra2D"; + int w = 1280; + int h = 720; + WindowMode mode = WindowMode::Windowed; + bool vsync = true; + int priority = 0; + }; }; // 不好的做法:所有配置放在 AppConfig struct AppConfig { - WindowConfigData window; // 耦合度高 - RenderConfigData render; + WindowConfig window; // 耦合度高 + RenderConfig render; // ... 新增模块需要修改 AppConfig }; ``` @@ -970,7 +1000,7 @@ window_->onResize([this, cameraService](int width, int height) { - [examples/basic/main.cpp](../../examples/basic/main.cpp) - 基础示例(场景图、输入事件、视口适配) - [Extra2D/src/platform/window_module.cpp](../../Extra2D/src/platform/window_module.cpp) - Window 模块实现 - [Extra2D/src/platform/input_module.cpp](../../Extra2D/src/platform/input_module.cpp) - Input 模块实现 -- [Extra2D/src/graphics/render_module.cpp](../../Extra2D/src/graphics/render_module.cpp) - Render 模块实现 +- [Extra2D/src/graphics/core/render_module.cpp](../../Extra2D/src/graphics/core/render_module.cpp) - Render 模块实现 - [Extra2D/src/scene/node.cpp](../../Extra2D/src/scene/node.cpp) - Node 实现 - [Extra2D/src/scene/shape_node.cpp](../../Extra2D/src/scene/shape_node.cpp) - ShapeNode 实现 diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp index e4f2112..9227865 100644 --- a/examples/basic/main.cpp +++ b/examples/basic/main.cpp @@ -1,22 +1,19 @@ /** * @file main.cpp * @brief Extra2D 场景图测试示例 - * - * 演示场景图功能: - * - 节点层级关系 - * - 变换(位置、旋转、缩放) - * - 形状节点渲染 - * - 输入事件处理 */ #include +#include +#include +#include +#include +#include +#include #include using namespace extra2d; -/** - * @brief 创建场景图测试 - */ void createSceneGraph(Scene *scene) { float width = scene->getWidth(); float height = scene->getHeight(); @@ -85,7 +82,7 @@ void createSceneGraph(Scene *scene) { std::cout << " └── Root (center)" << std::endl; std::cout << " ├── Parent1 (left)" << std::endl; std::cout << " │ ├── RedRect (100x100)" << std::endl; - std::cout << " │ └── Child1 (rotated 45°, scaled 0.5)" << std::endl; + std::cout << " │ └── Child1 (rotated 45, scaled 0.5)" << std::endl; std::cout << " │ └── OrangeRect (60x60)" << std::endl; std::cout << " ├── Parent2 (right)" << std::endl; std::cout << " │ ├── BlueCircle (radius 60)" << std::endl; @@ -96,35 +93,46 @@ void createSceneGraph(Scene *scene) { std::cout << "=============================\n" << std::endl; } -/** - * @brief 主函数 - */ int main(int argc, char *argv[]) { (void)argc; (void)argv; std::cout << "Extra2D Scene Graph Demo - Starting..." << std::endl; - AppConfig config = AppConfig::createDefault(); - config.appName = "Extra2D Scene Graph Demo"; - config.appVersion = "1.0.0"; - Application &app = Application::get(); - if (!app.init(config)) { + // 注册模块(按优先级顺序) + WindowModule::Cfg winCfg; + winCfg.w = 1280; + winCfg.h = 720; + winCfg.priority = 0; + app.use(winCfg); + + RenderModule::Cfg renderCfg; + renderCfg.priority = 10; + app.use(renderCfg); + + InputModule::Cfg inputCfg; + inputCfg.priority = 20; + app.use(inputCfg); + + std::cout << "Initializing application..." << std::endl; + if (!app.init()) { std::cerr << "Failed to initialize application!" << std::endl; return -1; } std::cout << "Application initialized successfully!" << std::endl; - std::cout << "Window: " << app.window().width() << "x" - << app.window().height() << std::endl; + + auto* win = app.window(); + if (win) { + std::cout << "Window: " << win->width() << "x" << win->height() << std::endl; + } - auto eventService = app.events(); + auto eventService = ServiceLocator::instance().getService(); if (eventService) { eventService->addListener(EventType::KeyPressed, [](Event &e) { auto &keyEvent = std::get(e.data); - if (keyEvent.keyCode == static_cast(Key::Escape)) { e.handled = true; Application::get().quit(); @@ -141,22 +149,23 @@ int main(int argc, char *argv[]) { auto scene = Scene::create(); scene->setBackgroundColor(Color(0.12f, 0.12f, 0.16f, 1.0f)); - scene->setViewportSize(static_cast(app.window().width()), - static_cast(app.window().height())); + if (win) { + scene->setViewportSize(static_cast(win->width()), + static_cast(win->height())); + } - auto cameraService = app.camera(); - if (cameraService) { + auto cameraService = ServiceLocator::instance().getService(); + if (cameraService && win) { ViewportConfig vpConfig; - vpConfig.logicWidth = static_cast(app.window().width()); - vpConfig.logicHeight = static_cast(app.window().height()); + vpConfig.logicWidth = static_cast(win->width()); + vpConfig.logicHeight = static_cast(win->height()); vpConfig.mode = ViewportMode::AspectRatio; cameraService->setViewportConfig(vpConfig); - cameraService->updateViewport(app.window().width(), app.window().height()); + cameraService->updateViewport(win->width(), win->height()); cameraService->applyViewportAdapter(); } createSceneGraph(scene.get()); - app.enterScene(scene); std::cout << "\nControls:" << std::endl; diff --git a/examples/hello_module/hello_module.cpp b/examples/hello_module/hello_module.cpp index 50456da..6bb6172 100644 --- a/examples/hello_module/hello_module.cpp +++ b/examples/hello_module/hello_module.cpp @@ -1,183 +1,38 @@ #include "hello_module.h" -#include -#include -#include - -using json = nlohmann::json; +#include namespace extra2d { -static ModuleId s_helloModuleId = INVALID_MODULE_ID; +HelloModule::HelloModule(const Cfg& cfg) : cfg_(cfg) {} -/** - * @brief 获取Hello模块标识符 - */ -ModuleId get_hello_module_id() { - return s_helloModuleId; -} - -/** - * @brief 从JSON加载配置 - */ -bool HelloModuleConfig::loadFromJson(const void* jsonData) { - if (!jsonData) return false; - - try { - const json& j = *static_cast(jsonData); - - if (j.contains("greeting")) { - config.greeting = j["greeting"].get(); - } - if (j.contains("repeatCount")) { - config.repeatCount = j["repeatCount"].get(); - } - if (j.contains("enableLogging")) { - config.enableLogging = j["enableLogging"].get(); - } - - return true; - } catch (...) { - return false; - } -} - -/** - * @brief 保存配置到JSON - */ -bool HelloModuleConfig::saveToJson(void* jsonData) const { - if (!jsonData) return false; - - try { - json& j = *static_cast(jsonData); - j["greeting"] = config.greeting; - j["repeatCount"] = config.repeatCount; - j["enableLogging"] = config.enableLogging; - return true; - } catch (...) { - return false; - } -} - -/** - * @brief 构造函数 - */ -HelloModuleInitializer::HelloModuleInitializer() - : moduleId_(INVALID_MODULE_ID) - , initialized_(false) { -} - -/** - * @brief 析构函数 - */ -HelloModuleInitializer::~HelloModuleInitializer() { +HelloModule::~HelloModule() { if (initialized_) { shutdown(); } } -/** - * @brief 获取模块依赖列表 - */ -std::vector HelloModuleInitializer::getDependencies() const { - return {}; -} - -/** - * @brief 初始化模块 - */ -bool HelloModuleInitializer::initialize(const IModuleConfig* config) { - if (initialized_) { - E2D_LOG_WARN("HelloModule already initialized"); - return true; - } +bool HelloModule::init() { + if (initialized_) return true; - if (!config) { - E2D_LOG_ERROR("HelloModule config is null"); - return false; - } - - const HelloModuleConfig* helloConfig = dynamic_cast(config); - if (!helloConfig) { - E2D_LOG_ERROR("Invalid HelloModule config type"); - return false; - } - - if (!helloConfig->validate()) { - E2D_LOG_ERROR("HelloModule config validation failed"); - return false; - } - - config_ = helloConfig->config; + std::cout << "HelloModule initialized" << std::endl; + std::cout << " Greeting: " << cfg_.greeting << std::endl; + std::cout << " Repeat count: " << cfg_.repeatCount << std::endl; initialized_ = true; - - E2D_LOG_INFO("HelloModule initialized"); - E2D_LOG_INFO(" Greeting: {}", config_.greeting); - E2D_LOG_INFO(" Repeat Count: {}", config_.repeatCount); - E2D_LOG_INFO(" Logging Enabled: {}", config_.enableLogging); - - sayHello(); - return true; } -/** - * @brief 关闭模块 - */ -void HelloModuleInitializer::shutdown() { +void HelloModule::shutdown() { if (!initialized_) return; - if (config_.enableLogging) { - E2D_LOG_INFO("HelloModule shutdown - Goodbye!"); - } - + std::cout << "HelloModule shutdown" << std::endl; initialized_ = false; } -/** - * @brief 执行问候操作 - */ -void HelloModuleInitializer::sayHello() const { - if (!config_.enableLogging) return; - - for (int i = 0; i < config_.repeatCount; ++i) { - E2D_LOG_INFO("[HelloModule] {}", config_.greeting); +void HelloModule::sayHello() const { + for (int i = 0; i < cfg_.repeatCount; ++i) { + std::cout << cfg_.greeting << std::endl; } } -/** - * @brief 注册Hello模块 - */ -void register_hello_module() { - if (s_helloModuleId != INVALID_MODULE_ID) { - E2D_LOG_WARN("HelloModule already registered"); - return; - } - - s_helloModuleId = ModuleRegistry::instance().registerModule( - makeUnique(), - []() -> UniquePtr { - auto initializer = makeUnique(); - initializer->setModuleId(s_helloModuleId); - return initializer; - } - ); - - E2D_LOG_DEBUG("HelloModule registered with id: {}", s_helloModuleId); -} - -namespace { - /** - * @brief 自动注册器 - * 在程序启动时自动注册模块 - */ - struct HelloModuleAutoRegister { - HelloModuleAutoRegister() { - register_hello_module(); - } - }; - - static HelloModuleAutoRegister s_autoRegister; -} - } // namespace extra2d diff --git a/examples/hello_module/hello_module.h b/examples/hello_module/hello_module.h index 9a75f15..253e910 100644 --- a/examples/hello_module/hello_module.h +++ b/examples/hello_module/hello_module.h @@ -1,148 +1,50 @@ #pragma once -#include -#include +#include #include namespace extra2d { /** - * @brief Hello模块配置数据结构 + * @brief Hello模块示例 + * 展示如何创建自定义模块 */ -struct HelloModuleConfigData { - std::string greeting = "Hello, Extra2D!"; - int repeatCount = 1; - bool enableLogging = true; -}; - -/** - * @brief Hello模块配置类 - * - * 这是一个简单的自定义模块示例,展示如何: - * 1. 定义模块配置数据结构 - * 2. 实现IModuleConfig接口 - * 3. 支持JSON配置加载/保存 - */ -class HelloModuleConfig : public IModuleConfig { +class HelloModule : public Module { public: - HelloModuleConfigData config; - /** - * @brief 获取模块信息 + * @brief 配置结构 */ - ModuleInfo getModuleInfo() const override { - ModuleInfo info; - info.id = 0; - info.name = "HelloModule"; - info.version = "1.0.0"; - info.priority = ModulePriority::User; - info.enabled = true; - return info; - } - + struct Cfg { + std::string greeting = "Hello, Extra2D!"; + int repeatCount = 1; + int priority = 100; + }; + /** - * @brief 获取配置节名称 + * @brief 构造函数 + * @param cfg 配置 */ - std::string getConfigSectionName() const override { - return "hello"; - } - + explicit HelloModule(const Cfg& cfg = Cfg{}); + /** - * @brief 验证配置有效性 - */ - bool validate() const override { - return !config.greeting.empty() && config.repeatCount > 0; - } - - /** - * @brief 重置为默认配置 - */ - void resetToDefaults() override { - config = HelloModuleConfigData{}; - } - - /** - * @brief 应用平台约束 - */ - void applyPlatformConstraints(PlatformType platform) override { - (void)platform; - } - - /** - * @brief 从JSON加载配置 - */ - bool loadFromJson(const void* jsonData) override; - - /** - * @brief 保存配置到JSON - */ - bool saveToJson(void* jsonData) const override; -}; - -/** - * @brief Hello模块初始化器 - * - * 负责模块的生命周期管理 - */ -class HelloModuleInitializer : public IModuleInitializer { -public: - HelloModuleInitializer(); - ~HelloModuleInitializer() override; - - /** - * @brief 获取模块标识符 - */ - ModuleId getModuleId() const override { return moduleId_; } - - /** - * @brief 获取模块优先级 - */ - ModulePriority getPriority() const override { return ModulePriority::User; } - - /** - * @brief 获取模块依赖列表 - */ - std::vector getDependencies() const override; - - /** - * @brief 初始化模块 - */ - bool initialize(const IModuleConfig* config) override; - - /** - * @brief 关闭模块 + * @brief 析构函数 */ + ~HelloModule() override; + + bool init() override; void shutdown() override; - - /** - * @brief 检查是否已初始化 - */ - bool isInitialized() const override { return initialized_; } - - /** - * @brief 设置模块标识符 - */ - void setModuleId(ModuleId id) { moduleId_ = id; } - + bool ok() const override { return initialized_; } + const char* name() const override { return "hello"; } + int priority() const override { return cfg_.priority; } + /** * @brief 执行问候操作 */ void sayHello() const; private: - ModuleId moduleId_ = INVALID_MODULE_ID; + Cfg cfg_; bool initialized_ = false; - HelloModuleConfigData config_; }; -/** - * @brief 获取Hello模块标识符 - */ -ModuleId get_hello_module_id(); - -/** - * @brief 注册Hello模块 - */ -void register_hello_module(); - } // namespace extra2d diff --git a/examples/hello_module/main.cpp b/examples/hello_module/main.cpp index 738e20d..8d1a649 100644 --- a/examples/hello_module/main.cpp +++ b/examples/hello_module/main.cpp @@ -1,52 +1,38 @@ #include "hello_module.h" #include -#include +#include +#include #include #include -#include +#include using namespace extra2d; -/** - * @brief 自定义场景类 - * - * 展示如何在场景中使用自定义模块 - */ class HelloScene : public Scene { public: static Ptr create() { return makeShared(); } void onEnter() override { Scene::onEnter(); - E2D_LOG_INFO("HelloScene entered"); - + std::cout << "HelloScene entered" << std::endl; setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f)); - ModuleId helloId = get_hello_module_id(); - auto *initializer = ModuleRegistry::instance().getInitializer(helloId); - if (initializer) { - auto *helloInit = dynamic_cast(initializer); - if (helloInit) { - E2D_LOG_INFO("Scene calling HelloModule from onEnter..."); - helloInit->sayHello(); - } + auto* hello = Application::get().get(); + if (hello) { + std::cout << "Scene calling HelloModule from onEnter..." << std::endl; + hello->sayHello(); } } void onUpdate(float dt) override { Scene::onUpdate(dt); - time_ += dt; if (time_ >= 5.0f) { - ModuleId helloId = get_hello_module_id(); - auto *initializer = ModuleRegistry::instance().getInitializer(helloId); - if (initializer) { - auto *helloInit = dynamic_cast(initializer); - if (helloInit) { - E2D_LOG_INFO("Scene calling HelloModule from onUpdate..."); - helloInit->sayHello(); - } + auto* hello = Application::get().get(); + if (hello) { + std::cout << "Scene calling HelloModule from onUpdate..." << std::endl; + hello->sayHello(); } time_ = 0.0f; } @@ -56,46 +42,41 @@ private: float time_ = 0.0f; }; -/** - * @brief 应用程序入口 - */ int main(int argc, char *argv[]) { (void)argc; (void)argv; - E2D_LOG_INFO("=== Hello Module Example ==="); - E2D_LOG_INFO("This example demonstrates how to create a custom module"); - E2D_LOG_INFO(""); + std::cout << "=== Hello Module Example ===" << std::endl; + std::cout << "This example demonstrates how to create a custom module" << std::endl; + std::cout << "" << std::endl; Application &app = Application::get(); - AppConfig appConfig; - appConfig.appName = "HelloModule Example"; - appConfig.appVersion = "1.0.0"; + // 注册模块 + app.use(WindowModule::Cfg{.w = 800, .h = 600}); + app.use(); + app.use(HelloModule::Cfg{.greeting = "Hello from custom module!", .repeatCount = 3}); - if (!app.init(appConfig)) { - E2D_LOG_ERROR("Failed to initialize application"); + if (!app.init()) { + std::cerr << "Failed to initialize application" << std::endl; return 1; } - E2D_LOG_INFO(""); - E2D_LOG_INFO("Application initialized successfully"); - E2D_LOG_INFO("HelloModule should have been auto-registered and initialized"); - E2D_LOG_INFO(""); + std::cout << "" << std::endl; + std::cout << "Application initialized successfully" << std::endl; + std::cout << "" << std::endl; auto scene = HelloScene::create(); app.enterScene(scene); - E2D_LOG_INFO("Starting main loop..."); - E2D_LOG_INFO("Press ESC or close window to exit"); - E2D_LOG_INFO(""); + std::cout << "Starting main loop..." << std::endl; + std::cout << "Press ESC or close window to exit" << std::endl; + std::cout << "" << std::endl; app.run(); - E2D_LOG_INFO("Application shutting down..."); - + std::cout << "Application shutting down..." << std::endl; app.shutdown(); - - E2D_LOG_INFO("Application shutdown complete"); + std::cout << "Application shutdown complete" << std::endl; return 0; }