diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8ccfaf7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,86 @@ +# CLAUDE.md + +本文件为 Claude Code (claude.ai/code) 在此仓库中工作时提供指导。 + +## 项目概述 + +Extra2D 是一个使用 C++17 编写的轻量级跨平台 2D 游戏引擎。支持 Windows (MinGW)、Linux、macOS 和 Nintendo Switch。项目注释和文档使用中文。 + +## 构建系统 + +项目使用 **xmake**(非 CMake)。 + +```bash +# 配置 (Windows/MinGW 示例) +xmake f -p mingw -a x86_64 -m release -y + +# 配置调试构建 +xmake f -p mingw -a x86_64 -m debug -y + +# 构建全部 +xmake build + +# 构建特定目标 +xmake build demo_basic +xmake build demo_hello_module + +# 运行示例 +xmake run demo_basic +xmake run demo_hello_module + +# Nintendo Switch 构建 +export DEVKITPRO=/opt/devkitpro +xmake f -p switch -m release -y +xmake build +``` + +构建目标:`extra2d`(引擎静态库)、`demo_basic`、`demo_hello_module`、`hello_module_lib`。 + +调试构建定义 `E2D_DEBUG` 和 `_DEBUG`。`debug_logs` 选项启用调试日志。 + +## 架构 + +### 双系统设计:模块 + 服务 + +引擎有两个由 `Application`(单例)管理的并行系统: + +- **模块**(`Module` 基类):处理平台级初始化,具有生命周期钩子(`setupModule`、`destroyModule`、`onUpdate`、`onRender`、`handleEvent`)。通过 `E2D_MODULE` 宏注册,在静态初始化时自动发现。按优先级排序(数值越小越先初始化)。 +- **服务**(`IService` 基类):提供通过 `ServiceLocator` 访问的运行时功能。通过 `Application` 便捷方法获取:`app.scenes()`、`app.timers()`、`app.events()`、`app.camera()`。 + +### 模块自动注册 + +模块使用 `E2D_MODULE(类名, 优先级)` 宏,放置在 `.cpp` 文件末尾、**任何命名空间之外**。这会创建一个静态的 `ModuleAutoRegister` 变量,在静态初始化期间向 `ModuleRegistry` 注册。静态链接需要 `--whole-archive` 链接器标志,以防止链接器剥离这些未引用的符号。 + +内置模块优先级顺序:Logger(-1) → Config(0) → Platform(10) → Window(20) → Input(30) → Render(40)。用户模块应使用优先级 1000+。 + +### 模块上下文链 + +模块生命周期方法接收上下文对象(`UpdateContext`、`RenderContext`、`EventContext`)。**必须调用 `ctx.next()`** 以继续链式调用到下一个模块。 + +### 关键子系统 + +- **平台层**:统一的 SDL2 后端(`E2D_BACKEND_SDL2` 宏定义)。通过 `IWindow`/`IInput` 接口实现平台抽象。实现在 `Extra2D/src/platform/backends/sdl2/`。 +- **图形**:通过 glad 使用 OpenGL ES 3.2。渲染器(`gl_renderer`)、精灵批处理(`gl_sprite_batch`)、支持热重载的着色器管理。内置着色器在 `Extra2D/shaders/builtin/`(构建后复制到构建目录)。 +- **场景图**:基于树的 `Node` 层级结构,支持变换继承。`Scene` 是根节点。专用节点:`ShapeNode`、`Sprite`。场景过渡效果(淡入淡出、滑动、翻转、缩放、方块)。 +- **事件系统**:`EventType` 枚举驱动。事件使用 `std::variant` 实现类型化数据(`KeyEvent`、`MouseEvent`、`GamepadEvent`)。输入使用扫描码(非键码)。 + +## 源码布局 + +- `Extra2D/include/extra2d/` — 按子系统组织的公共头文件 +- `Extra2D/src/` — 实现,镜像 include 结构 +- `Extra2D/shaders/` — GLSL 着色器文件(复制到构建输出) +- `examples/` — 示例程序(`basic/`、`hello_module/`) +- `xmake/engine.lua` — 引擎静态库目标定义 +- `xmake.lua` — 根构建配置,包含示例目标 + +## 依赖 + +由 xmake 管理:`glm`、`nlohmann_json`、`libsdl2`。内嵌:`glad`、`stb_image`、`stb_truetype`、`stb_rect_pack`、`KHR`。 + +## 约定 + +- 命名空间:`extra2d` +- 智能指针:`Ptr`(shared_ptr 别名)、`SharedPtr`,通过 `makeShared()` 创建 +- 日志:`E2D_LOG_INFO(...)`、`E2D_LOG_WARN(...)`、`E2D_LOG_ERROR(...)` +- 导出宏:`E2D_API` 用于 DLL 可见符号 +- 自定义模块直接编译到可执行文件(静态链接,推荐)或作为独立 DLL diff --git a/Extra2D/include/extra2d/config/app_config.h b/Extra2D/include/extra2d/config/app_config.h index a8cbde7..f81e319 100644 --- a/Extra2D/include/extra2d/config/app_config.h +++ b/Extra2D/include/extra2d/config/app_config.h @@ -9,12 +9,9 @@ namespace extra2d { /** * @file app_config.h * @brief 应用级别配置 - * + * * 本文件仅包含应用级别的配置项,不包含任何模块特定配置。 - * 各模块应该在自己的模块文件中定义配置结构,并实现 IModuleConfig 接口。 - * - * 模块配置通过 ModuleRegistry 注册,由 ConfigManager 统一管理。 - * 这种设计遵循开闭原则,新增模块无需修改引擎核心代码。 + * 各模块在自己的模块头文件中定义配置结构(如 RenderModuleConfig)。 */ /** diff --git a/Extra2D/include/extra2d/config/config_loader.h b/Extra2D/include/extra2d/config/config_loader.h index 50af30c..8d2eb7f 100644 --- a/Extra2D/include/extra2d/config/config_loader.h +++ b/Extra2D/include/extra2d/config/config_loader.h @@ -9,9 +9,8 @@ namespace extra2d { /** * @file config_loader.h * @brief 配置加载器接口 - * - * 配置加载器只负责加载应用级别的配置(AppConfig)。 - * 模块配置通过 ModuleRegistry 和各模块的 IModuleConfig 接口加载。 + * + * 负责加载和保存应用级别的配置(AppConfig)。 */ /** diff --git a/Extra2D/include/extra2d/config/config_manager.h b/Extra2D/include/extra2d/config/config_manager.h index 6b44658..ee864bc 100644 --- a/Extra2D/include/extra2d/config/config_manager.h +++ b/Extra2D/include/extra2d/config/config_manager.h @@ -12,9 +12,8 @@ namespace extra2d { /** * @file config_manager.h * @brief 配置管理器 - * - * 配置管理器只管理应用级别的配置(AppConfig)。 - * 模块配置通过 ModuleRegistry 管理,各模块实现 IModuleConfig 接口。 + * + * 管理应用级别的配置(AppConfig)。 */ /** diff --git a/Extra2D/include/extra2d/core/module.h b/Extra2D/include/extra2d/core/module.h index 31f46de..6979002 100644 --- a/Extra2D/include/extra2d/core/module.h +++ b/Extra2D/include/extra2d/core/module.h @@ -2,7 +2,6 @@ #include #include -#include #include namespace extra2d { @@ -10,8 +9,6 @@ namespace extra2d { class Module; class UpdateContext; class RenderContext; -class EventContext; - /** * @brief 模块上下文基类 * 用于遍历模块链,支持链式调用 @@ -112,22 +109,6 @@ private: Phase phase_; }; -/** - * @brief 事件上下文 - * 用于模块事件处理阶段 - */ -class EventContext : public ModuleContext { -public: - /** - * @brief 构造函数 - * @param modules 模块列表引用 - */ - EventContext(std::vector& modules); - -protected: - void handle(Module* m) override; -}; - /** * @brief 模块基类 * 所有模块只需继承此类,实现需要的生命周期方法 @@ -179,13 +160,6 @@ public: */ virtual void afterRender(RenderContext& ctx) { ctx.next(); } - /** - * @brief 事件处理 - * 处理系统事件 - * @param ctx 事件上下文 - */ - virtual void handleEvent(EventContext& ctx) { ctx.next(); } - /** * @brief 获取模块名称 * @return 模块名称字符串 diff --git a/Extra2D/include/extra2d/core/module_macros.h b/Extra2D/include/extra2d/core/module_macros.h index dbb3dc0..b133562 100644 --- a/Extra2D/include/extra2d/core/module_macros.h +++ b/Extra2D/include/extra2d/core/module_macros.h @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -20,20 +19,13 @@ public: const char* name_ = nullptr; int priority_ = 0; std::vector dependencies_; - std::function bindFunc_; - + const char* getName() const override { return name_; } int getPriority() const override { return priority_; } std::vector getDependencies() const override { return dependencies_; } - - T* create() override { - return new T(); - } - - void bindProperties(Module* instance, PropertyBinder& binder) override { - if (bindFunc_) { - bindFunc_(instance, binder); - } + + T* create() override { + return new T(); } }; @@ -107,50 +99,3 @@ struct ModuleAutoRegister { E2D_DECLARE_FORCE_LINK(ModuleClassName); \ E2D_CALL_FORCE_LINK(ModuleClassName) -/** - * @brief 带属性的模块定义开始 - */ -#define E2D_MODULE_BEGIN(ModuleClassName) \ - namespace { \ - static ::extra2d::ModuleMeta< ::extra2d::ModuleClassName>& E2D_CONCAT(_e2d_get_meta_, ModuleClassName)() { \ - static ::extra2d::ModuleMeta< ::extra2d::ModuleClassName> meta; \ - return meta; \ - } \ - struct E2D_CONCAT(_E2D_ModuleCfg_, ModuleClassName) { \ - E2D_CONCAT(_E2D_ModuleCfg_, ModuleClassName)() - -/** - * @brief 定义模块优先级 - */ -#define E2D_PRIORITY(value) \ - { auto& m = E2D_CONCAT(_e2d_get_meta_, ModuleClassName)(); m.priority_ = value; } - -/** - * @brief 定义模块依赖 - */ -#define E2D_DEPENDENCIES(...) \ - { \ - auto& m = E2D_CONCAT(_e2d_get_meta_, ModuleClassName)(); \ - m.dependencies_ = { __VA_ARGS__ }; \ - } - -/** - * @brief 定义属性 - */ -#define E2D_PROPERTY(name, type) \ - { \ - auto& m = E2D_CONCAT(_e2d_get_meta_, ModuleClassName)(); \ - auto oldFunc = m.bindFunc_; \ - m.bindFunc_ = [oldFunc](::extra2d::Module* inst, ::extra2d::PropertyBinder& binder) { \ - if (oldFunc) oldFunc(inst, binder); \ - auto* module = static_cast< ::extra2d::ModuleClassName*>(inst); \ - binder.bind(#name, module->name, #name, ""); \ - }; \ - } - -/** - * @brief 结束模块定义 - */ -#define E2D_MODULE_END() \ - } E2D_CONCAT(_e2d_cfg_inst_, ModuleClassName); \ - } diff --git a/Extra2D/include/extra2d/core/module_meta.h b/Extra2D/include/extra2d/core/module_meta.h index 3088166..6ef288b 100644 --- a/Extra2D/include/extra2d/core/module_meta.h +++ b/Extra2D/include/extra2d/core/module_meta.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -43,10 +42,6 @@ struct E2D_API ModuleMetaBase { */ virtual Module* create() = 0; - /** - * @brief 绑定模块属性 - */ - virtual void bindProperties(Module* instance, PropertyBinder& binder) = 0; }; /** diff --git a/Extra2D/include/extra2d/core/property.h b/Extra2D/include/extra2d/core/property.h deleted file mode 100644 index f4e2bc0..0000000 --- a/Extra2D/include/extra2d/core/property.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -namespace extra2d { - -/** - * @brief 属性值类型 - * - * 支持多种基础类型的运行时存储和查询 - */ -using PropertyValue = std::variant< - std::monostate, - bool, - int, - float, - double, - std::string, - Vec2, - Vec3, - Color, - Rect, - Size ->; - -/** - * @brief 属性元数据 - * - * 包含属性的描述信息,用于编辑器和序列化 - */ -struct PropertyMeta { - const char* name = nullptr; - const char* displayName = nullptr; - const char* description = nullptr; - PropertyValue defaultValue{}; - bool editable = true; - bool serializable = true; - - PropertyMeta() = default; - - PropertyMeta(const char* n, const char* dn, const char* desc, - PropertyValue def, bool edit = true, bool ser = true) - : name(n), displayName(dn), description(desc), - defaultValue(def), editable(edit), serializable(ser) {} -}; - -/** - * @brief 属性访问器 - * - * 用于运行时读写属性值 - */ -struct PropertyAccessor { - std::function getter; - std::function setter; - PropertyMeta meta; -}; - -/** - * @brief 属性绑定器基类 - * - * 提供属性的绑定、查询和修改接口 - */ -class PropertyBinder { -public: - virtual ~PropertyBinder() = default; - - /** - * @brief 获取所有属性元数据 - * @return 属性元数据列表 - */ - virtual std::vector getProperties() const = 0; - - /** - * @brief 获取属性值 - * @param name 属性名 - * @return 属性值 - */ - virtual PropertyValue getProperty(const char* name) const = 0; - - /** - * @brief 设置属性值 - * @param name 属性名 - * @param value 属性值 - * @return 设置成功返回 true - */ - virtual bool setProperty(const char* name, const PropertyValue& value) = 0; - - /** - * @brief 检查是否有指定属性 - * @param name 属性名 - * @return 存在返回 true - */ - virtual bool hasProperty(const char* name) const = 0; - - /** - * @brief 获取属性元数据 - * @param name 属性名 - * @return 属性元数据指针,不存在返回 nullptr - */ - virtual const PropertyMeta* getPropertyMeta(const char* name) const = 0; -}; - -/** - * @brief 属性绑定器实现 - * - * 使用函数指针实现属性的运行时访问 - */ -class PropertyBinderImpl : public PropertyBinder { -public: - /** - * @brief 绑定属性 - * @tparam T 属性类型 - * @param name 属性名 - * @param value 属性引用 - * @param displayName 显示名 - * @param description 描述 - */ - template - void bind(const char* name, T& value, - const char* displayName = nullptr, - const char* description = nullptr) { - PropertyAccessor accessor; - accessor.meta = PropertyMeta(name, displayName ? displayName : name, - description ? description : "", T{}); - accessor.getter = [&value]() -> PropertyValue { return value; }; - accessor.setter = [&value](const PropertyValue& v) -> bool { - if (auto* ptr = std::get_if(&v)) { - value = *ptr; - return true; - } - return false; - }; - accessors_[name] = std::move(accessor); - } - - std::vector getProperties() const override { - std::vector result; - result.reserve(accessors_.size()); - for (const auto& [name, accessor] : accessors_) { - result.push_back(accessor.meta); - } - return result; - } - - PropertyValue getProperty(const char* name) const override { - auto it = accessors_.find(name); - if (it != accessors_.end() && it->second.getter) { - return it->second.getter(); - } - return {}; - } - - bool setProperty(const char* name, const PropertyValue& value) override { - auto it = accessors_.find(name); - if (it != accessors_.end() && it->second.setter) { - return it->second.setter(value); - } - return false; - } - - bool hasProperty(const char* name) const override { - return accessors_.find(name) != accessors_.end(); - } - - const PropertyMeta* getPropertyMeta(const char* name) const override { - auto it = accessors_.find(name); - if (it != accessors_.end()) { - return &it->second.meta; - } - return nullptr; - } - -private: - std::unordered_map accessors_; -}; - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/core/service_registry.h b/Extra2D/include/extra2d/core/service_registry.h deleted file mode 100644 index 7ce4964..0000000 --- a/Extra2D/include/extra2d/core/service_registry.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace extra2d { - -/** - * @brief 服务注册信息 - */ -struct ServiceRegistration { - std::string name; - ServicePriority priority; - std::function()> factory; - bool enabled = true; -}; - -/** - * @brief 服务注册表 - * 管理服务的注册信息,支持延迟创建和配置 - */ -class ServiceRegistry { -public: - /** - * @brief 获取单例实例 - * @return 服务注册表实例引用 - */ - static ServiceRegistry& instance(); - - ServiceRegistry(const ServiceRegistry&) = delete; - ServiceRegistry& operator=(const ServiceRegistry&) = delete; - - /** - * @brief 注册服务 - * @tparam T 服务接口类型 - * @tparam Impl 服务实现类型 - * @param name 服务名称 - * @param priority 服务优先级 - */ - template - void registerService(const std::string& name, ServicePriority priority) { - static_assert(std::is_base_of_v, - "T must derive from IService"); - static_assert(std::is_base_of_v, - "Impl must derive from T"); - - ServiceRegistration reg; - reg.name = name; - reg.priority = priority; - reg.factory = []() -> SharedPtr { - return std::static_pointer_cast(makeShared()); - }; - registrations_.push_back(reg); - } - - /** - * @brief 注册服务(带工厂函数) - * @tparam T 服务接口类型 - * @param name 服务名称 - * @param priority 服务优先级 - * @param factory 工厂函数 - */ - template - void registerServiceWithFactory( - const std::string& name, - ServicePriority priority, - std::function()> factory) { - static_assert(std::is_base_of_v, - "T must derive from IService"); - - ServiceRegistration reg; - reg.name = name; - reg.priority = priority; - reg.factory = [factory]() -> SharedPtr { - return std::static_pointer_cast(factory()); - }; - registrations_.push_back(reg); - } - - /** - * @brief 启用/禁用服务 - * @param name 服务名称 - * @param enabled 是否启用 - */ - void setServiceEnabled(const std::string& name, bool enabled); - - /** - * @brief 创建所有已注册的服务 - * 并注册到 ServiceLocator - */ - void createAllServices(); - - /** - * @brief 获取所有注册信息 - * @return 注册信息列表 - */ - const std::vector& getRegistrations() const { - return registrations_; - } - - /** - * @brief 清空所有注册 - */ - void clear() { - registrations_.clear(); - } - -private: - ServiceRegistry() = default; - ~ServiceRegistry() = default; - - std::vector registrations_; -}; - -/** - * @brief 自动服务注册器 - * 在全局作用域使用,自动注册服务 - */ -template -class AutoServiceRegistrar { -public: - AutoServiceRegistrar(const std::string& name, ServicePriority priority) { - ServiceRegistry::instance().registerService( - name, priority); - } -}; - -} - -#define E2D_REGISTER_SERVICE_AUTO(Interface, Implementation, Name, Priority) \ - namespace { \ - static ::extra2d::AutoServiceRegistrar \ - E2D_CONCAT(auto_service_registrar_, __LINE__)(Name, Priority); \ - } 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 37031b2..5700344 100644 --- a/Extra2D/include/extra2d/extra2d.h +++ b/Extra2D/include/extra2d/extra2d.h @@ -49,8 +49,6 @@ // Event #include -#include -#include // Utils #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/shader_cache.h b/Extra2D/include/extra2d/graphics/shader_cache.h deleted file mode 100644 index 1ab93f5..0000000 --- a/Extra2D/include/extra2d/graphics/shader_cache.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace extra2d { - -// ============================================================================ -// Shader缓存条目 -// ============================================================================ -struct ShaderCacheEntry { - std::string name; - std::string sourceHash; - uint64_t compileTime = 0; - std::vector binary; - std::vector dependencies; -}; - -// ============================================================================ -// Shader缓存管理器 -// ============================================================================ -class ShaderCache { -public: - /** - * @brief 获取单例实例 - * @return 缓存管理器实例引用 - */ - static ShaderCache& getInstance(); - - /** - * @brief 初始化缓存系统 - * @param cacheDir 缓存目录路径 - * @return 初始化成功返回true,失败返回false - */ - bool init(const std::string& cacheDir); - - /** - * @brief 关闭缓存系统 - */ - void shutdown(); - - /** - * @brief 检查缓存是否有效 - * @param name Shader名称 - * @param sourceHash 源码哈希值 - * @return 缓存有效返回true,否则返回false - */ - bool hasValidCache(const std::string& name, const std::string& sourceHash); - - /** - * @brief 加载缓存的二进制数据 - * @param name Shader名称 - * @return 缓存条目指针,不存在返回nullptr - */ - Ptr loadCache(const std::string& name); - - /** - * @brief 保存编译结果到缓存 - * @param entry 缓存条目 - * @return 保存成功返回true,失败返回false - */ - bool saveCache(const ShaderCacheEntry& entry); - - /** - * @brief 使缓存失效 - * @param name Shader名称 - */ - void invalidate(const std::string& name); - - /** - * @brief 清除所有缓存 - */ - void clearAll(); - - /** - * @brief 计算源码哈希值 - * @param vertSource 顶点着色器源码 - * @param fragSource 片段着色器源码 - * @return 哈希值字符串 - */ - static std::string computeHash(const std::string& vertSource, - const std::string& fragSource); - - /** - * @brief 检查是否已初始化 - * @return 已初始化返回true,否则返回false - */ - bool isInitialized() const { return initialized_; } - -private: - ShaderCache() = default; - ~ShaderCache() = default; - ShaderCache(const ShaderCache&) = delete; - ShaderCache& operator=(const ShaderCache&) = delete; - - std::string cacheDir_; - std::unordered_map cacheMap_; - bool initialized_ = false; - - /** - * @brief 加载缓存索引 - * @return 加载成功返回true,失败返回false - */ - bool loadCacheIndex(); - - /** - * @brief 保存缓存索引 - * @return 保存成功返回true,失败返回false - */ - bool saveCacheIndex(); - - /** - * @brief 获取缓存文件路径 - * @param name Shader名称 - * @return 缓存文件完整路径 - */ - std::string getCachePath(const std::string& name) const; - - /** - * @brief 确保缓存目录存在 - * @return 目录存在或创建成功返回true,否则返回false - */ - bool ensureCacheDirectory(); -}; - -// 便捷宏 -#define E2D_SHADER_CACHE() ::extra2d::ShaderCache::getInstance() - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/shader_hot_reloader.h b/Extra2D/include/extra2d/graphics/shader_hot_reloader.h deleted file mode 100644 index d5ddebc..0000000 --- a/Extra2D/include/extra2d/graphics/shader_hot_reloader.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -namespace extra2d { - -// ============================================================================ -// 文件变化事件 -// ============================================================================ -struct FileChangeEvent { - std::string filepath; - - enum class Type { - Created, - Modified, - Deleted, - Renamed - } type; - - uint64_t timestamp = 0; -}; - -// ============================================================================ -// 文件变化回调 -// ============================================================================ -using FileChangeCallback = std::function; - -// ============================================================================ -// Shader热重载管理器 -// ============================================================================ -class ShaderHotReloader { -public: - /** - * @brief 获取单例实例 - * @return 热重载管理器实例引用 - */ - static ShaderHotReloader& getInstance(); - - /** - * @brief 初始化热重载系统 - * @return 初始化成功返回true,失败返回false - */ - bool init(); - - /** - * @brief 关闭热重载系统 - */ - void shutdown(); - - /** - * @brief 注册Shader文件监视 - * @param shaderName Shader名称 - * @param filePaths 要监视的文件列表 - * @param callback 文件变化时的回调 - */ - void watch(const std::string& shaderName, - const std::vector& filePaths, - FileChangeCallback callback); - - /** - * @brief 取消监视 - * @param shaderName Shader名称 - */ - void unwatch(const std::string& shaderName); - - /** - * @brief 更新文件监视(在主循环中调用) - */ - void update(); - - /** - * @brief 启用/禁用热重载 - * @param enabled 是否启用 - */ - void setEnabled(bool enabled); - - /** - * @brief 检查是否启用 - * @return 启用返回true,否则返回false - */ - bool isEnabled() const { return enabled_; } - - /** - * @brief 检查是否已初始化 - * @return 已初始化返回true,否则返回false - */ - bool isInitialized() const { return initialized_; } - -private: - ShaderHotReloader() = default; - ~ShaderHotReloader() = default; - ShaderHotReloader(const ShaderHotReloader&) = delete; - ShaderHotReloader& operator=(const ShaderHotReloader&) = delete; - - bool enabled_ = false; - bool initialized_ = false; - - struct WatchInfo { - std::vector filePaths; - FileChangeCallback callback; - std::unordered_map modifiedTimes; - }; - std::unordered_map watchMap_; - -#ifdef _WIN32 - HANDLE watchHandle_ = nullptr; - std::vector buffer_; - std::string watchDir_; - bool watching_ = false; -#endif - - /** - * @brief 轮询检查文件变化 - */ - void pollChanges(); - - /** - * @brief 获取文件修改时间 - * @param filepath 文件路径 - * @return 修改时间戳 - */ - static uint64_t getFileModifiedTime(const std::string& filepath); -}; - -// 便捷宏 -#define E2D_SHADER_HOT_RELOADER() ::extra2d::ShaderHotReloader::getInstance() - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/shader_loader.h b/Extra2D/include/extra2d/graphics/shader_loader.h index 3f8bdc3..29d7d10 100644 --- a/Extra2D/include/extra2d/graphics/shader_loader.h +++ b/Extra2D/include/extra2d/graphics/shader_loader.h @@ -32,136 +32,34 @@ struct ShaderMetadata { }; // ============================================================================ -// ShaderLoader接口 - 支持多种文件格式加载 +// ShaderLoader - Shader文件加载 // ============================================================================ -class IShaderLoader { -public: - virtual ~IShaderLoader() = default; - - /** - * @brief 从分离文件加载Shader (.vert + .frag) - * @param name Shader名称 - * @param vertPath 顶点着色器文件路径 - * @param fragPath 片段着色器文件路径 - * @return 加载结果 - */ - virtual ShaderLoadResult loadFromSeparateFiles( - const std::string& name, - const std::string& vertPath, - const std::string& fragPath) = 0; - - /** - * @brief 从组合文件加载Shader (.shader) - * @param path 组合Shader文件路径 - * @return 加载结果 - */ - virtual ShaderLoadResult loadFromCombinedFile(const std::string& path) = 0; - - /** - * @brief 从源码字符串加载Shader - * @param vertSource 顶点着色器源码 - * @param fragSource 片段着色器源码 - * @return 加载结果 - */ - virtual ShaderLoadResult loadFromSource( - const std::string& vertSource, - const std::string& fragSource) = 0; - - /** - * @brief 处理Shader源码中的#include指令 - * @param source 原始源码 - * @param baseDir 基础目录 - * @param outDependencies 输出依赖列表 - * @return 处理后的源码 - */ - virtual std::string processIncludes( - const std::string& source, - const std::string& baseDir, - std::vector& outDependencies) = 0; - - /** - * @brief 应用预处理器定义 - * @param source 原始源码 - * @param defines 预处理器定义列表 - * @return 处理后的源码 - */ - virtual std::string applyDefines( - const std::string& source, - const std::vector& defines) = 0; - - /** - * @brief 获取Shader元数据 - * @param path Shader文件路径 - * @return 元数据 - */ - virtual ShaderMetadata getMetadata(const std::string& path) = 0; -}; - -// ============================================================================ -// 默认ShaderLoader实现 -// ============================================================================ -class ShaderLoader : public IShaderLoader { +class ShaderLoader { public: ShaderLoader(); - ~ShaderLoader() override = default; + ~ShaderLoader() = default; - /** - * @brief 从分离文件加载Shader (.vert + .frag) - * @param name Shader名称 - * @param vertPath 顶点着色器文件路径 - * @param fragPath 片段着色器文件路径 - * @return 加载结果 - */ ShaderLoadResult loadFromSeparateFiles( const std::string& name, const std::string& vertPath, - const std::string& fragPath) override; + const std::string& fragPath); - /** - * @brief 从组合文件加载Shader (.shader) - * @param path 组合Shader文件路径 - * @return 加载结果 - */ - ShaderLoadResult loadFromCombinedFile(const std::string& path) override; + ShaderLoadResult loadFromCombinedFile(const std::string& path); - /** - * @brief 从源码字符串加载Shader - * @param vertSource 顶点着色器源码 - * @param fragSource 片段着色器源码 - * @return 加载结果 - */ ShaderLoadResult loadFromSource( const std::string& vertSource, - const std::string& fragSource) override; + const std::string& fragSource); - /** - * @brief 处理Shader源码中的#include指令 - * @param source 原始源码 - * @param baseDir 基础目录 - * @param outDependencies 输出依赖列表 - * @return 处理后的源码 - */ std::string processIncludes( const std::string& source, const std::string& baseDir, - std::vector& outDependencies) override; + std::vector& outDependencies); - /** - * @brief 应用预处理器定义 - * @param source 原始源码 - * @param defines 预处理器定义列表 - * @return 处理后的源码 - */ std::string applyDefines( const std::string& source, - const std::vector& defines) override; + const std::vector& defines); - /** - * @brief 获取Shader元数据 - * @param path Shader文件路径 - * @return 元数据 - */ - ShaderMetadata getMetadata(const std::string& path) override; + ShaderMetadata getMetadata(const std::string& path); /** * @brief 添加include搜索路径 diff --git a/Extra2D/include/extra2d/graphics/shader_manager.h b/Extra2D/include/extra2d/graphics/shader_manager.h index b7a5761..677a648 100644 --- a/Extra2D/include/extra2d/graphics/shader_manager.h +++ b/Extra2D/include/extra2d/graphics/shader_manager.h @@ -1,21 +1,52 @@ #pragma once -#include -#include #include #include #include #include +#include + +#ifdef _WIN32 +#include +#endif namespace extra2d { +// ============================================================================ +// Shader缓存条目 +// ============================================================================ +struct ShaderCacheEntry { + std::string name; + std::string sourceHash; + uint64_t compileTime = 0; + std::vector binary; + std::vector dependencies; +}; + +// ============================================================================ +// 文件变化事件 +// ============================================================================ +struct FileChangeEvent { + std::string filepath; + + enum class Type { + Created, + Modified, + Deleted, + Renamed + } type; + + uint64_t timestamp = 0; +}; + // ============================================================================ // Shader重载回调 // ============================================================================ using ShaderReloadCallback = std::function newShader)>; +using FileChangeCallback = std::function; // ============================================================================ -// Shader管理器 - 统一入口 +// Shader管理器 - 统一入口(加载/缓存/热重载) // ============================================================================ class ShaderManager { public: @@ -31,7 +62,6 @@ public: /** * @brief 使用平台默认路径初始化Shader系统 - * 自动检测平台并使用正确的路径(romfs/sdmc/相对路径) * @param factory 渲染后端Shader工厂 * @param appName 应用名称(用于缓存目录) * @return 初始化成功返回true,失败返回false @@ -56,14 +86,11 @@ public: /** * @brief 检查是否已初始化 - * @return 已初始化返回true,否则返回false */ bool isInitialized() const { return initialized_; } /** * @brief 检查当前平台是否支持热重载 - * Switch平台使用romfs,不支持热重载 - * @return 支持热重载返回true */ bool isHotReloadSupported() const { return hotReloadSupported_; } @@ -71,134 +98,73 @@ public: // Shader加载 // ------------------------------------------------------------------------ - /** - * @brief 从分离文件加载Shader - * @param name Shader名称 - * @param vertPath 顶点着色器文件路径 - * @param fragPath 片段着色器文件路径 - * @return 加载的Shader实例 - */ Ptr loadFromFiles(const std::string& name, const std::string& vertPath, const std::string& fragPath); - /** - * @brief 从组合文件加载Shader - * @param path 组合Shader文件路径 - * @return 加载的Shader实例 - */ Ptr loadFromCombinedFile(const std::string& path); - /** - * @brief 从源码加载Shader - * @param name Shader名称 - * @param vertSource 顶点着色器源码 - * @param fragSource 片段着色器源码 - * @return 加载的Shader实例 - */ Ptr loadFromSource(const std::string& name, const std::string& vertSource, const std::string& fragSource); - /** - * @brief 获取已加载的Shader - * @param name Shader名称 - * @return Shader实例,不存在返回nullptr - */ Ptr get(const std::string& name) const; - - /** - * @brief 检查Shader是否存在 - * @param name Shader名称 - * @return 存在返回true,否则返回false - */ bool has(const std::string& name) const; - - /** - * @brief 移除Shader - * @param name Shader名称 - */ void remove(const std::string& name); - - /** - * @brief 清除所有Shader - */ void clear(); // ------------------------------------------------------------------------ // 热重载 // ------------------------------------------------------------------------ - /** - * @brief 注册重载回调 - * @param name Shader名称 - * @param callback 重载回调函数 - */ void setReloadCallback(const std::string& name, ShaderReloadCallback callback); - - /** - * @brief 启用/禁用热重载 - * @param enabled 是否启用 - */ void setHotReloadEnabled(bool enabled); - - /** - * @brief 检查热重载是否启用 - * @return 启用返回true,否则返回false - */ bool isHotReloadEnabled() const; - - /** - * @brief 更新热重载系统(主循环调用) - */ void update(); - - /** - * @brief 手动重载Shader - * @param name Shader名称 - * @return 重载成功返回true,失败返回false - */ bool reload(const std::string& name); + // ------------------------------------------------------------------------ + // 热重载文件监视 + // ------------------------------------------------------------------------ + + void watch(const std::string& shaderName, + const std::vector& filePaths, + FileChangeCallback callback); + void unwatch(const std::string& shaderName); + // ------------------------------------------------------------------------ // 内置Shader // ------------------------------------------------------------------------ - /** - * @brief 获取内置Shader - * @param name 内置Shader名称 - * @return Shader实例 - */ Ptr getBuiltin(const std::string& name); - - /** - * @brief 加载所有内置Shader - * @return 加载成功返回true,失败返回false - */ bool loadBuiltinShaders(); // ------------------------------------------------------------------------ // 工具方法 // ------------------------------------------------------------------------ - /** - * @brief 获取Shader目录 - * @return Shader目录路径 - */ const std::string& getShaderDir() const { return shaderDir_; } - - /** - * @brief 获取ShaderLoader - * @return ShaderLoader引用 - */ ShaderLoader& getLoader() { return loader_; } + // ------------------------------------------------------------------------ + // 缓存 + // ------------------------------------------------------------------------ + + bool hasValidCache(const std::string& name, const std::string& sourceHash); + Ptr loadCache(const std::string& name); + bool saveCache(const ShaderCacheEntry& entry); + void invalidateCache(const std::string& name); + void clearAllCache(); + static std::string computeHash(const std::string& vertSource, + const std::string& fragSource); + private: ShaderManager() = default; ~ShaderManager() = default; ShaderManager(const ShaderManager&) = delete; ShaderManager& operator=(const ShaderManager&) = delete; + // Shader存储 std::string shaderDir_; std::string cacheDir_; Ptr factory_; @@ -218,29 +184,45 @@ private: bool hotReloadEnabled_ = false; bool hotReloadSupported_ = true; - /** - * @brief 从缓存加载Shader - * @param name Shader名称 - * @param sourceHash 源码哈希值 - * @param vertSource 顶点着色器源码 - * @param fragSource 片段着色器源码 - * @return Shader实例 - */ + // 缓存(原 ShaderCache) + std::unordered_map cacheMap_; + bool cacheInitialized_ = false; + + bool initCache(const std::string& cacheDir); + void shutdownCache(); + bool loadCacheIndex(); + bool saveCacheIndex(); + std::string getCachePath(const std::string& name) const; + bool ensureCacheDirectory(); + + // 热重载(原 ShaderHotReloader) + bool reloaderInitialized_ = false; + + struct WatchInfo { + std::vector filePaths; + FileChangeCallback callback; + std::unordered_map modifiedTimes; + }; + std::unordered_map watchMap_; + +#ifdef _WIN32 + HANDLE watchHandle_ = nullptr; + std::vector watchBuffer_; + std::string watchDir_; + bool watching_ = false; +#endif + + bool initReloader(); + void shutdownReloader(); + void pollChanges(); + static uint64_t getFileModifiedTime(const std::string& filepath); + Ptr loadFromCache(const std::string& name, const std::string& sourceHash, const std::string& vertSource, const std::string& fragSource); - /** - * @brief 创建内置Shader源码 - */ void createBuiltinShaderSources(); - - /** - * @brief 处理文件变化事件 - * @param shaderName Shader名称 - * @param event 文件变化事件 - */ void handleFileChange(const std::string& shaderName, const FileChangeEvent& event); }; diff --git a/Extra2D/include/extra2d/graphics/shader_preset.h b/Extra2D/include/extra2d/graphics/shader_preset.h deleted file mode 100644 index 18dd3fc..0000000 --- a/Extra2D/include/extra2d/graphics/shader_preset.h +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace extra2d { - -struct WaterParams { - float waveSpeed = 1.0f; - float waveAmplitude = 0.02f; - float waveFrequency = 4.0f; -}; - -struct OutlineParams { - Color color = Colors::Black; - float thickness = 2.0f; -}; - -struct DistortionParams { - float distortionAmount = 0.02f; - float timeScale = 1.0f; -}; - -struct PixelateParams { - float pixelSize = 8.0f; -}; - -struct InvertParams { - float strength = 1.0f; -}; - -struct GrayscaleParams { - float intensity = 1.0f; -}; - -struct BlurParams { - float radius = 5.0f; -}; - -class ShaderPreset { -public: - /** - * @brief 创建水波纹效果着色器 - * @param params 水波纹效果参数 - * @return 配置好的着色器 - */ - static Ptr Water(const WaterParams& params = {}); - - /** - * @brief 创建描边效果着色器 - * @param params 描边效果参数 - * @return 配置好的着色器 - */ - static Ptr Outline(const OutlineParams& params = {}); - - /** - * @brief 创建扭曲效果着色器 - * @param params 扭曲效果参数 - * @return 配置好的着色器 - */ - static Ptr Distortion(const DistortionParams& params = {}); - - /** - * @brief 创建像素化效果着色器 - * @param params 像素化效果参数 - * @return 配置好的着色器 - */ - static Ptr Pixelate(const PixelateParams& params = {}); - - /** - * @brief 创建反相效果着色器 - * @param params 反相效果参数 - * @return 配置好的着色器 - */ - static Ptr Invert(const InvertParams& params = {}); - - /** - * @brief 创建灰度效果着色器 - * @param params 灰度效果参数 - * @return 配置好的着色器 - */ - static Ptr Grayscale(const GrayscaleParams& params = {}); - - /** - * @brief 创建模糊效果着色器 - * @param params 模糊效果参数 - * @return 配置好的着色器 - */ - static Ptr Blur(const BlurParams& params = {}); - - /** - * @brief 创建灰度+描边组合效果着色器 - * @param grayParams 灰度效果参数 - * @param outlineParams 描边效果参数 - * @return 配置好的着色器 - */ - static Ptr GrayscaleOutline(const GrayscaleParams& grayParams, - const OutlineParams& outlineParams); - - /** - * @brief 创建像素化+反相组合效果着色器 - * @param pixParams 像素化效果参数 - * @param invParams 反相效果参数 - * @return 配置好的着色器 - */ - static Ptr PixelateInvert(const PixelateParams& pixParams, - const InvertParams& invParams); -}; - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/texture_pool.h b/Extra2D/include/extra2d/graphics/texture_pool.h index 2bc517e..2897fa9 100644 --- a/Extra2D/include/extra2d/graphics/texture_pool.h +++ b/Extra2D/include/extra2d/graphics/texture_pool.h @@ -382,6 +382,12 @@ public: */ void init(Scene* scene, size_t maxMemoryUsage = 0); + /** + * @brief 设置渲染后端 + * @param backend 渲染后端指针 + */ + void setRenderBackend(RenderBackend* backend) { backend_ = backend; } + // ======================================================================== // 纹理加载 // ======================================================================== @@ -554,6 +560,7 @@ private: void tryAutoEvict(); Scene* scene_; // 场景指针 + RenderBackend* backend_ = nullptr; // 渲染后端 mutable std::mutex mutex_; // 互斥锁 std::unordered_map cache_; // 纹理缓存 diff --git a/Extra2D/include/extra2d/modules/render_module.h b/Extra2D/include/extra2d/modules/render_module.h index 07be5ff..c908f8f 100644 --- a/Extra2D/include/extra2d/modules/render_module.h +++ b/Extra2D/include/extra2d/modules/render_module.h @@ -1,8 +1,9 @@ #pragma once #include -#include +#include #include +#include namespace extra2d { @@ -16,6 +17,27 @@ struct RenderModuleConfig { int multisamples = 0; bool sRGBFramebuffer = false; int spriteBatchSize = 1000; + bool tripleBuffering = 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 maxRenderTargets = 1; + bool allowShaderHotReload = false; + std::string shaderCachePath; + + /** + * @brief 检查是否启用多重采样 + */ + bool isMultisampleEnabled() const { return multisamples > 0; } + + /** + * @brief 检查是否限制帧率 + */ + bool isFPSCapped() const { return targetFPS > 0; } /** * @brief 验证配置有效性 @@ -25,16 +47,16 @@ struct RenderModuleConfig { if (targetFPS < 1 || targetFPS > 240) { return false; } - - if (multisamples != 0 && multisamples != 2 && multisamples != 4 && + + if (multisamples != 0 && multisamples != 2 && multisamples != 4 && multisamples != 8 && multisamples != 16) { return false; } - + if (spriteBatchSize <= 0) { return false; } - + return true; } }; 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/services/event_service.h b/Extra2D/include/extra2d/services/event_service.h index 7b91819..bf4944e 100644 --- a/Extra2D/include/extra2d/services/event_service.h +++ b/Extra2D/include/extra2d/services/event_service.h @@ -60,11 +60,6 @@ public: size_t getTotalListenerCount() const override; size_t getQueueSize() const override; - EventQueue& getQueue() { return queue_; } - const EventQueue& getQueue() const { return queue_; } - EventDispatcher& getDispatcher() { return dispatcher_; } - const EventDispatcher& getDispatcher() const { return dispatcher_; } - private: EventQueue queue_; EventDispatcher dispatcher_; diff --git a/Extra2D/src/app/application.cpp b/Extra2D/src/app/application.cpp index 8b93f1b..59cf932 100644 --- a/Extra2D/src/app/application.cpp +++ b/Extra2D/src/app/application.cpp @@ -256,9 +256,6 @@ void Application::mainLoop() { render(); - auto renderModule = getModule(); - (void)renderModule; - ConfigManager::instance().update(deltaTime_); } @@ -331,11 +328,8 @@ RenderBackend &Application::renderer() { if (renderModule && renderModule->getRenderer()) { return *renderModule->getRenderer(); } - static RenderBackend *dummy = nullptr; - if (!dummy) { - dummy = RenderBackend::create(BackendType::OpenGL).release(); - } - return *dummy; + E2D_LOG_ERROR("RenderModule not initialized - renderer() called too early"); + std::abort(); } SharedPtr Application::scenes() { diff --git a/Extra2D/src/core/module.cpp b/Extra2D/src/core/module.cpp index 5d232d8..cf5fab0 100644 --- a/Extra2D/src/core/module.cpp +++ b/Extra2D/src/core/module.cpp @@ -54,16 +54,4 @@ void RenderContext::handle(Module* m) { } } -// --------------------------------------------------------------------------- -// EventContext 实现 -// --------------------------------------------------------------------------- - -EventContext::EventContext(std::vector& modules) - : ModuleContext(modules) { -} - -void EventContext::handle(Module* m) { - m->handleEvent(*this); -} - } // namespace extra2d diff --git a/Extra2D/src/core/module_registry.cpp b/Extra2D/src/core/module_registry.cpp index fa7d671..25b3198 100644 --- a/Extra2D/src/core/module_registry.cpp +++ b/Extra2D/src/core/module_registry.cpp @@ -205,9 +205,6 @@ bool ModuleRegistry::createAndInitAll() { continue; } - PropertyBinderImpl binder; - meta->bindProperties(instance, binder); - instance->setupModule(); instances_.emplace_back(instance); diff --git a/Extra2D/src/core/service_registry.cpp b/Extra2D/src/core/service_registry.cpp deleted file mode 100644 index 752de31..0000000 --- a/Extra2D/src/core/service_registry.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include - -namespace extra2d { - -ServiceRegistry& ServiceRegistry::instance() { - static ServiceRegistry instance; - return instance; -} - -void ServiceRegistry::setServiceEnabled(const std::string& name, bool enabled) { - for (auto& reg : registrations_) { - if (reg.name == name) { - reg.enabled = enabled; - break; - } - } -} - -void ServiceRegistry::createAllServices() { - std::sort(registrations_.begin(), registrations_.end(), - [](const ServiceRegistration& a, const ServiceRegistration& b) { - return static_cast(a.priority) < static_cast(b.priority); - }); - - for (const auto& reg : registrations_) { - if (!reg.enabled) { - continue; - } - - auto service = reg.factory(); - if (service) { - ServiceLocator::instance().registerService(service); - } - } -} - -} 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/shader_cache.cpp b/Extra2D/src/graphics/shader_cache.cpp deleted file mode 100644 index b77c61d..0000000 --- a/Extra2D/src/graphics/shader_cache.cpp +++ /dev/null @@ -1,286 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace extra2d { - -namespace fs = std::filesystem; - -/** - * @brief 获取单例实例 - * @return 缓存管理器实例引用 - */ -ShaderCache& ShaderCache::getInstance() { - static ShaderCache instance; - return instance; -} - -/** - * @brief 初始化缓存系统 - * @param cacheDir 缓存目录路径 - * @return 初始化成功返回true,失败返回false - */ -bool ShaderCache::init(const std::string& cacheDir) { - cacheDir_ = cacheDir; - - if (!ensureCacheDirectory()) { - E2D_LOG_ERROR("Failed to create cache directory: {}", cacheDir); - return false; - } - - if (!loadCacheIndex()) { - E2D_LOG_WARN("Failed to load cache index, starting fresh"); - } - - initialized_ = true; - E2D_LOG_INFO("Shader cache initialized at: {}", cacheDir); - return true; -} - -/** - * @brief 关闭缓存系统 - */ -void ShaderCache::shutdown() { - if (!initialized_) { - return; - } - - saveCacheIndex(); - cacheMap_.clear(); - initialized_ = false; - E2D_LOG_INFO("Shader cache shutdown"); -} - -/** - * @brief 检查缓存是否有效 - * @param name Shader名称 - * @param sourceHash 源码哈希值 - * @return 缓存有效返回true,否则返回false - */ -bool ShaderCache::hasValidCache(const std::string& name, const std::string& sourceHash) { - auto it = cacheMap_.find(name); - if (it == cacheMap_.end()) { - return false; - } - - return it->second.sourceHash == sourceHash; -} - -/** - * @brief 加载缓存的二进制数据 - * @param name Shader名称 - * @return 缓存条目指针,不存在返回nullptr - */ -Ptr ShaderCache::loadCache(const std::string& name) { - auto it = cacheMap_.find(name); - if (it == cacheMap_.end()) { - return nullptr; - } - - std::string cachePath = getCachePath(name); - std::ifstream file(cachePath, std::ios::binary); - if (!file.is_open()) { - E2D_LOG_WARN("Failed to open cache file: {}", cachePath); - return nullptr; - } - - auto entry = std::make_shared(it->second); - entry->binary.clear(); - - file.seekg(0, std::ios::end); - size_t fileSize = static_cast(file.tellg()); - file.seekg(0, std::ios::beg); - - entry->binary.resize(fileSize); - file.read(reinterpret_cast(entry->binary.data()), fileSize); - - return entry; -} - -/** - * @brief 保存编译结果到缓存 - * @param entry 缓存条目 - * @return 保存成功返回true,失败返回false - */ -bool ShaderCache::saveCache(const ShaderCacheEntry& entry) { - if (!initialized_) { - E2D_LOG_WARN("ShaderCache not initialized, cannot save cache"); - return false; - } - - if (entry.binary.empty()) { - E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", entry.name); - return false; - } - - std::string cachePath = getCachePath(entry.name); - E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, entry.binary.size()); - - std::ofstream file(cachePath, std::ios::binary); - if (!file.is_open()) { - E2D_LOG_ERROR("Failed to create cache file: {}", cachePath); - return false; - } - - file.write(reinterpret_cast(entry.binary.data()), entry.binary.size()); - file.close(); - - cacheMap_[entry.name] = entry; - saveCacheIndex(); - - E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name, entry.binary.size()); - return true; -} - -/** - * @brief 使缓存失效 - * @param name Shader名称 - */ -void ShaderCache::invalidate(const std::string& name) { - auto it = cacheMap_.find(name); - if (it == cacheMap_.end()) { - return; - } - - std::string cachePath = getCachePath(name); - fs::remove(cachePath); - - cacheMap_.erase(it); - saveCacheIndex(); - - E2D_LOG_DEBUG("Shader cache invalidated: {}", name); -} - -/** - * @brief 清除所有缓存 - */ -void ShaderCache::clearAll() { - for (const auto& pair : cacheMap_) { - std::string cachePath = getCachePath(pair.first); - fs::remove(cachePath); - } - - cacheMap_.clear(); - saveCacheIndex(); - - E2D_LOG_INFO("All shader caches cleared"); -} - -/** - * @brief 计算源码哈希值 - * @param vertSource 顶点着色器源码 - * @param fragSource 片段着色器源码 - * @return 哈希值字符串 - */ -std::string ShaderCache::computeHash(const std::string& vertSource, - const std::string& fragSource) { - std::string combined = vertSource + fragSource; - - uint32_t hash = 5381; - for (char c : combined) { - hash = ((hash << 5) + hash) + static_cast(c); - } - - std::stringstream ss; - ss << std::hex << hash; - return ss.str(); -} - -/** - * @brief 加载缓存索引 - * @return 加载成功返回true,失败返回false - */ -bool ShaderCache::loadCacheIndex() { - std::string indexPath = cacheDir_ + "/.cache_index"; - - if (!fs::exists(indexPath)) { - return true; - } - - std::ifstream file(indexPath); - if (!file.is_open()) { - return false; - } - - std::string line; - while (std::getline(file, line)) { - if (line.empty() || line[0] == '#') { - continue; - } - - size_t pos = line.find('='); - if (pos == std::string::npos) { - continue; - } - - std::string name = line.substr(0, pos); - std::string hash = line.substr(pos + 1); - - std::string cachePath = getCachePath(name); - if (fs::exists(cachePath)) { - ShaderCacheEntry entry; - entry.name = name; - entry.sourceHash = hash; - entry.compileTime = static_cast( - std::chrono::system_clock::now().time_since_epoch().count()); - cacheMap_[name] = entry; - } - } - - return true; -} - -/** - * @brief 保存缓存索引 - * @return 保存成功返回true,失败返回false - */ -bool ShaderCache::saveCacheIndex() { - std::string indexPath = cacheDir_ + "/.cache_index"; - - std::ofstream file(indexPath); - if (!file.is_open()) { - return false; - } - - file << "# Extra2D Shader Cache Index\n"; - file << "# Format: name=hash\n"; - - for (const auto& pair : cacheMap_) { - file << pair.first << "=" << pair.second.sourceHash << "\n"; - } - - return true; -} - -/** - * @brief 获取缓存文件路径 - * @param name Shader名称 - * @return 缓存文件完整路径 - */ -std::string ShaderCache::getCachePath(const std::string& name) const { - return cacheDir_ + "/" + name + ".cache"; -} - -/** - * @brief 确保缓存目录存在 - * @return 目录存在或创建成功返回true,否则返回false - */ -bool ShaderCache::ensureCacheDirectory() { - if (cacheDir_.empty()) { - return false; - } - - std::error_code ec; - if (!fs::exists(cacheDir_)) { - if (!fs::create_directories(cacheDir_, ec)) { - return false; - } - } - - return true; -} - -} // namespace extra2d diff --git a/Extra2D/src/graphics/shader_hot_reloader.cpp b/Extra2D/src/graphics/shader_hot_reloader.cpp deleted file mode 100644 index 867ad84..0000000 --- a/Extra2D/src/graphics/shader_hot_reloader.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include -#include -#include - -namespace extra2d { - -namespace fs = std::filesystem; - -/** - * @brief 获取单例实例 - * @return 热重载管理器实例引用 - */ -ShaderHotReloader& ShaderHotReloader::getInstance() { - static ShaderHotReloader instance; - return instance; -} - -/** - * @brief 初始化热重载系统 - * @return 初始化成功返回true,失败返回false - */ -bool ShaderHotReloader::init() { - if (initialized_) { - return true; - } - -#ifdef _WIN32 - buffer_.resize(4096); -#endif - - initialized_ = true; - E2D_LOG_INFO("Shader hot reloader initialized"); - return true; -} - -/** - * @brief 关闭热重载系统 - */ -void ShaderHotReloader::shutdown() { - if (!initialized_) { - return; - } - -#ifdef _WIN32 - if (watchHandle_ != nullptr) { - FindCloseChangeNotification(watchHandle_); - watchHandle_ = nullptr; - } -#endif - - watchMap_.clear(); - initialized_ = false; - enabled_ = false; - E2D_LOG_INFO("Shader hot reloader shutdown"); -} - -/** - * @brief 注册Shader文件监视 - * @param shaderName Shader名称 - * @param filePaths 要监视的文件列表 - * @param callback 文件变化时的回调 - */ -void ShaderHotReloader::watch(const std::string& shaderName, - const std::vector& filePaths, - FileChangeCallback callback) { - if (!initialized_) { - E2D_LOG_WARN("Hot reloader not initialized"); - return; - } - - WatchInfo info; - info.filePaths = filePaths; - info.callback = callback; - - for (const auto& path : filePaths) { - info.modifiedTimes[path] = getFileModifiedTime(path); - } - - watchMap_[shaderName] = std::move(info); - E2D_LOG_DEBUG("Watching shader: {} ({} files)", shaderName, filePaths.size()); -} - -/** - * @brief 取消监视 - * @param shaderName Shader名称 - */ -void ShaderHotReloader::unwatch(const std::string& shaderName) { - auto it = watchMap_.find(shaderName); - if (it != watchMap_.end()) { - watchMap_.erase(it); - E2D_LOG_DEBUG("Stopped watching shader: {}", shaderName); - } -} - -/** - * @brief 更新文件监视(在主循环中调用) - */ -void ShaderHotReloader::update() { - if (!initialized_ || !enabled_) { - return; - } - - pollChanges(); -} - -/** - * @brief 启用/禁用热重载 - * @param enabled 是否启用 - */ -void ShaderHotReloader::setEnabled(bool enabled) { - enabled_ = enabled; - E2D_LOG_DEBUG("Hot reload {}", enabled ? "enabled" : "disabled"); -} - -/** - * @brief 轮询检查文件变化 - */ -void ShaderHotReloader::pollChanges() { - auto now = static_cast( - std::chrono::system_clock::now().time_since_epoch().count()); - - for (auto& pair : watchMap_) { - WatchInfo& info = pair.second; - - for (const auto& filePath : info.filePaths) { - uint64_t currentModTime = getFileModifiedTime(filePath); - uint64_t lastModTime = info.modifiedTimes[filePath]; - - if (currentModTime != 0 && lastModTime != 0 && currentModTime != lastModTime) { - info.modifiedTimes[filePath] = currentModTime; - - FileChangeEvent event; - event.filepath = filePath; - event.type = FileChangeEvent::Type::Modified; - event.timestamp = now; - - E2D_LOG_DEBUG("Shader file changed: {}", filePath); - - if (info.callback) { - info.callback(event); - } - } - } - } -} - -/** - * @brief 获取文件修改时间 - * @param filepath 文件路径 - * @return 修改时间戳 - */ -uint64_t ShaderHotReloader::getFileModifiedTime(const std::string& filepath) { - try { - auto ftime = fs::last_write_time(filepath); - auto sctp = std::chrono::time_point_cast( - ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); - return static_cast(sctp.time_since_epoch().count()); - } catch (...) { - return 0; - } -} - -} // namespace extra2d diff --git a/Extra2D/src/graphics/shader_manager.cpp b/Extra2D/src/graphics/shader_manager.cpp index ac90f3f..5130331 100644 --- a/Extra2D/src/graphics/shader_manager.cpp +++ b/Extra2D/src/graphics/shader_manager.cpp @@ -1,8 +1,18 @@ #include #include +#include +#include +#include +#include namespace extra2d { +namespace fs = std::filesystem; + +// ============================================================================ +// ShaderManager 核心 +// ============================================================================ + ShaderManager& ShaderManager::getInstance() { static ShaderManager instance; return instance; @@ -11,7 +21,7 @@ ShaderManager& ShaderManager::getInstance() { bool ShaderManager::init(Ptr factory, const std::string& appName) { std::string shaderDir; std::string cacheDir; - + #ifdef __SWITCH__ shaderDir = "romfs:/shaders/"; cacheDir = "sdmc:/config/" + appName + "/shader_cache/"; @@ -23,7 +33,7 @@ bool ShaderManager::init(Ptr factory, const std::string& appName hotReloadSupported_ = true; E2D_LOG_INFO("Platform: Desktop (HotReload: supported)"); #endif - + return init(shaderDir, cacheDir, factory); } @@ -46,18 +56,16 @@ bool ShaderManager::init(const std::string& shaderDir, #ifdef __SWITCH__ hotReloadSupported_ = false; - if (!ShaderCache::getInstance().init(cacheDir_)) { - E2D_LOG_WARN("Failed to initialize shader cache on Switch"); - } #else hotReloadSupported_ = true; - if (!ShaderCache::getInstance().init(cacheDir_)) { - E2D_LOG_WARN("Failed to initialize shader cache, caching disabled"); - } #endif + if (!initCache(cacheDir_)) { + E2D_LOG_WARN("Failed to initialize shader cache, caching disabled"); + } + if (hotReloadSupported_) { - if (!ShaderHotReloader::getInstance().init()) { + if (!initReloader()) { E2D_LOG_WARN("Failed to initialize hot reloader"); } } @@ -66,7 +74,7 @@ bool ShaderManager::init(const std::string& shaderDir, initialized_ = true; E2D_LOG_INFO("ShaderManager initialized"); - + return true; } @@ -76,9 +84,9 @@ void ShaderManager::shutdown() { } if (hotReloadSupported_) { - ShaderHotReloader::getInstance().shutdown(); + shutdownReloader(); } - ShaderCache::getInstance().shutdown(); + shutdownCache(); shaders_.clear(); factory_.reset(); @@ -87,6 +95,10 @@ void ShaderManager::shutdown() { E2D_LOG_INFO("ShaderManager shutdown"); } +// ============================================================================ +// Shader 加载 +// ============================================================================ + Ptr ShaderManager::loadFromFiles(const std::string& name, const std::string& vertPath, const std::string& fragPath) { @@ -97,7 +109,7 @@ Ptr ShaderManager::loadFromFiles(const std::string& name, auto vertSource = loader_.readFile(vertPath); auto fragSource = loader_.readFile(fragPath); - + if (vertSource.empty() || fragSource.empty()) { E2D_LOG_ERROR("Failed to load shader sources: {} / {}", vertPath, fragPath); return nullptr; @@ -145,7 +157,7 @@ Ptr ShaderManager::loadFromSource(const std::string& name, info.shader = shader; info.vertSource = vertSource; info.fragSource = fragSource; - + shaders_[name] = std::move(info); E2D_LOG_INFO("Shader loaded: {}", name); @@ -177,6 +189,10 @@ void ShaderManager::clear() { E2D_LOG_INFO("All shaders cleared"); } +// ============================================================================ +// 热重载 +// ============================================================================ + void ShaderManager::setReloadCallback(const std::string& name, ShaderReloadCallback callback) { auto it = shaders_.find(name); if (it != shaders_.end()) { @@ -200,7 +216,9 @@ void ShaderManager::update() { if (!hotReloadEnabled_ || !hotReloadSupported_) { return; } - ShaderHotReloader::getInstance().update(); + if (reloaderInitialized_) { + pollChanges(); + } } bool ShaderManager::reload(const std::string& name) { @@ -217,7 +235,7 @@ bool ShaderManager::reload(const std::string& name) { } it->second.shader = shader; - + if (it->second.reloadCallback) { it->second.reloadCallback(shader); } @@ -226,13 +244,17 @@ bool ShaderManager::reload(const std::string& name) { return true; } +// ============================================================================ +// 内置Shader +// ============================================================================ + Ptr ShaderManager::getBuiltin(const std::string& name) { return get("builtin_" + name); } bool ShaderManager::loadBuiltinShaders() { E2D_LOG_INFO("Loading builtin shaders..."); - + const std::vector builtinShaders = { "sprite", "shape", @@ -240,7 +262,7 @@ bool ShaderManager::loadBuiltinShaders() { "particle", "postprocess" }; - + int loaded = 0; for (const auto& name : builtinShaders) { std::string path = shaderDir_ + "builtin/" + name + ".shader"; @@ -260,7 +282,7 @@ bool ShaderManager::loadBuiltinShaders() { } } } - + E2D_LOG_INFO("Builtin shaders loaded: {}/{}", loaded, builtinShaders.size()); return loaded > 0; } @@ -274,4 +296,321 @@ void ShaderManager::handleFileChange(const std::string& shaderName, const FileCh } } +// ============================================================================ +// 缓存(原 ShaderCache) +// ============================================================================ + +bool ShaderManager::initCache(const std::string& cacheDir) { + cacheDir_ = cacheDir; + + if (!ensureCacheDirectory()) { + E2D_LOG_ERROR("Failed to create cache directory: {}", cacheDir); + return false; + } + + if (!loadCacheIndex()) { + E2D_LOG_WARN("Failed to load cache index, starting fresh"); + } + + cacheInitialized_ = true; + E2D_LOG_INFO("Shader cache initialized at: {}", cacheDir); + return true; } + +void ShaderManager::shutdownCache() { + if (!cacheInitialized_) { + return; + } + + saveCacheIndex(); + cacheMap_.clear(); + cacheInitialized_ = false; + E2D_LOG_INFO("Shader cache shutdown"); +} + +bool ShaderManager::hasValidCache(const std::string& name, const std::string& sourceHash) { + auto it = cacheMap_.find(name); + if (it == cacheMap_.end()) { + return false; + } + return it->second.sourceHash == sourceHash; +} + +Ptr ShaderManager::loadCache(const std::string& name) { + auto it = cacheMap_.find(name); + if (it == cacheMap_.end()) { + return nullptr; + } + + std::string cachePath = getCachePath(name); + std::ifstream file(cachePath, std::ios::binary); + if (!file.is_open()) { + E2D_LOG_WARN("Failed to open cache file: {}", cachePath); + return nullptr; + } + + auto entry = std::make_shared(it->second); + entry->binary.clear(); + + file.seekg(0, std::ios::end); + size_t fileSize = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + + entry->binary.resize(fileSize); + file.read(reinterpret_cast(entry->binary.data()), fileSize); + + return entry; +} + +bool ShaderManager::saveCache(const ShaderCacheEntry& entry) { + if (!cacheInitialized_) { + E2D_LOG_WARN("Shader cache not initialized, cannot save cache"); + return false; + } + + if (entry.binary.empty()) { + E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", entry.name); + return false; + } + + std::string cachePath = getCachePath(entry.name); + E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, entry.binary.size()); + + std::ofstream file(cachePath, std::ios::binary); + if (!file.is_open()) { + E2D_LOG_ERROR("Failed to create cache file: {}", cachePath); + return false; + } + + file.write(reinterpret_cast(entry.binary.data()), entry.binary.size()); + file.close(); + + cacheMap_[entry.name] = entry; + saveCacheIndex(); + + E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name, entry.binary.size()); + return true; +} + +void ShaderManager::invalidateCache(const std::string& name) { + auto it = cacheMap_.find(name); + if (it == cacheMap_.end()) { + return; + } + + std::string cachePath = getCachePath(name); + fs::remove(cachePath); + + cacheMap_.erase(it); + saveCacheIndex(); + + E2D_LOG_DEBUG("Shader cache invalidated: {}", name); +} + +void ShaderManager::clearAllCache() { + for (const auto& pair : cacheMap_) { + std::string cachePath = getCachePath(pair.first); + fs::remove(cachePath); + } + + cacheMap_.clear(); + saveCacheIndex(); + + E2D_LOG_INFO("All shader caches cleared"); +} + +std::string ShaderManager::computeHash(const std::string& vertSource, + const std::string& fragSource) { + std::string combined = vertSource + fragSource; + + uint32_t hash = 5381; + for (char c : combined) { + hash = ((hash << 5) + hash) + static_cast(c); + } + + std::stringstream ss; + ss << std::hex << hash; + return ss.str(); +} + +bool ShaderManager::loadCacheIndex() { + std::string indexPath = cacheDir_ + "/.cache_index"; + + if (!fs::exists(indexPath)) { + return true; + } + + std::ifstream file(indexPath); + if (!file.is_open()) { + return false; + } + + std::string line; + while (std::getline(file, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + size_t pos = line.find('='); + if (pos == std::string::npos) { + continue; + } + + std::string name = line.substr(0, pos); + std::string hash = line.substr(pos + 1); + + std::string cachePath = getCachePath(name); + if (fs::exists(cachePath)) { + ShaderCacheEntry entry; + entry.name = name; + entry.sourceHash = hash; + entry.compileTime = static_cast( + std::chrono::system_clock::now().time_since_epoch().count()); + cacheMap_[name] = entry; + } + } + + return true; +} + +bool ShaderManager::saveCacheIndex() { + std::string indexPath = cacheDir_ + "/.cache_index"; + + std::ofstream file(indexPath); + if (!file.is_open()) { + return false; + } + + file << "# Extra2D Shader Cache Index\n"; + file << "# Format: name=hash\n"; + + for (const auto& pair : cacheMap_) { + file << pair.first << "=" << pair.second.sourceHash << "\n"; + } + + return true; +} + +std::string ShaderManager::getCachePath(const std::string& name) const { + return cacheDir_ + "/" + name + ".cache"; +} + +bool ShaderManager::ensureCacheDirectory() { + if (cacheDir_.empty()) { + return false; + } + + std::error_code ec; + if (!fs::exists(cacheDir_)) { + if (!fs::create_directories(cacheDir_, ec)) { + return false; + } + } + + return true; +} + +// ============================================================================ +// 热重载(原 ShaderHotReloader) +// ============================================================================ + +bool ShaderManager::initReloader() { + if (reloaderInitialized_) { + return true; + } + +#ifdef _WIN32 + watchBuffer_.resize(4096); +#endif + + reloaderInitialized_ = true; + E2D_LOG_INFO("Shader hot reloader initialized"); + return true; +} + +void ShaderManager::shutdownReloader() { + if (!reloaderInitialized_) { + return; + } + +#ifdef _WIN32 + if (watchHandle_ != nullptr) { + FindCloseChangeNotification(watchHandle_); + watchHandle_ = nullptr; + } +#endif + + watchMap_.clear(); + reloaderInitialized_ = false; + E2D_LOG_INFO("Shader hot reloader shutdown"); +} + +void ShaderManager::watch(const std::string& shaderName, + const std::vector& filePaths, + FileChangeCallback callback) { + if (!reloaderInitialized_) { + E2D_LOG_WARN("Hot reloader not initialized"); + return; + } + + WatchInfo info; + info.filePaths = filePaths; + info.callback = callback; + + for (const auto& path : filePaths) { + info.modifiedTimes[path] = getFileModifiedTime(path); + } + + watchMap_[shaderName] = std::move(info); + E2D_LOG_DEBUG("Watching shader: {} ({} files)", shaderName, filePaths.size()); +} + +void ShaderManager::unwatch(const std::string& shaderName) { + auto it = watchMap_.find(shaderName); + if (it != watchMap_.end()) { + watchMap_.erase(it); + E2D_LOG_DEBUG("Stopped watching shader: {}", shaderName); + } +} + +void ShaderManager::pollChanges() { + auto now = static_cast( + std::chrono::system_clock::now().time_since_epoch().count()); + + for (auto& pair : watchMap_) { + WatchInfo& info = pair.second; + + for (const auto& filePath : info.filePaths) { + uint64_t currentModTime = getFileModifiedTime(filePath); + uint64_t lastModTime = info.modifiedTimes[filePath]; + + if (currentModTime != 0 && lastModTime != 0 && currentModTime != lastModTime) { + info.modifiedTimes[filePath] = currentModTime; + + FileChangeEvent event; + event.filepath = filePath; + event.type = FileChangeEvent::Type::Modified; + event.timestamp = now; + + E2D_LOG_DEBUG("Shader file changed: {}", filePath); + + if (info.callback) { + info.callback(event); + } + } + } + } +} + +uint64_t ShaderManager::getFileModifiedTime(const std::string& filepath) { + try { + auto ftime = fs::last_write_time(filepath); + auto sctp = std::chrono::time_point_cast( + ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); + return static_cast(sctp.time_since_epoch().count()); + } catch (...) { + return 0; + } +} + +} // namespace extra2d diff --git a/Extra2D/src/graphics/shader_preset.cpp b/Extra2D/src/graphics/shader_preset.cpp deleted file mode 100644 index 5c590ab..0000000 --- a/Extra2D/src/graphics/shader_preset.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include -#include -#include - -namespace extra2d { - -/** - * @brief 创建水波纹效果着色器 - * @param params 水波纹效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Water(const WaterParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("water"); - if (!shader) { - E2D_LOG_ERROR("Failed to get water shader"); - return nullptr; - } - - shader->setFloat("u_waveSpeed", params.waveSpeed); - shader->setFloat("u_waveAmplitude", params.waveAmplitude); - shader->setFloat("u_waveFrequency", params.waveFrequency); - - return shader; -} - -/** - * @brief 创建描边效果着色器 - * @param params 描边效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Outline(const OutlineParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("outline"); - if (!shader) { - E2D_LOG_ERROR("Failed to get outline shader"); - return nullptr; - } - - shader->setVec4("u_outlineColor", glm::vec4(params.color.r, params.color.g, - params.color.b, params.color.a)); - shader->setFloat("u_thickness", params.thickness); - - return shader; -} - -/** - * @brief 创建扭曲效果着色器 - * @param params 扭曲效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Distortion(const DistortionParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("distortion"); - if (!shader) { - E2D_LOG_ERROR("Failed to get distortion shader"); - return nullptr; - } - - shader->setFloat("u_distortionAmount", params.distortionAmount); - shader->setFloat("u_timeScale", params.timeScale); - - return shader; -} - -/** - * @brief 创建像素化效果着色器 - * @param params 像素化效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Pixelate(const PixelateParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("pixelate"); - if (!shader) { - E2D_LOG_ERROR("Failed to get pixelate shader"); - return nullptr; - } - - shader->setFloat("u_pixelSize", params.pixelSize); - - return shader; -} - -/** - * @brief 创建反相效果着色器 - * @param params 反相效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Invert(const InvertParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("invert"); - if (!shader) { - E2D_LOG_ERROR("Failed to get invert shader"); - return nullptr; - } - - shader->setFloat("u_strength", params.strength); - - return shader; -} - -/** - * @brief 创建灰度效果着色器 - * @param params 灰度效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Grayscale(const GrayscaleParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("grayscale"); - if (!shader) { - E2D_LOG_ERROR("Failed to get grayscale shader"); - return nullptr; - } - - shader->setFloat("u_intensity", params.intensity); - - return shader; -} - -/** - * @brief 创建模糊效果着色器 - * @param params 模糊效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::Blur(const BlurParams ¶ms) { - Ptr shader = ShaderManager::getInstance().get("blur"); - if (!shader) { - E2D_LOG_ERROR("Failed to get blur shader"); - return nullptr; - } - - shader->setFloat("u_radius", params.radius); - - return shader; -} - -/** - * @brief 创建灰度+描边组合效果着色器 - * @param grayParams 灰度效果参数 - * @param outlineParams 描边效果参数 - * @return 配置好的着色器 - */ -Ptr -ShaderPreset::GrayscaleOutline(const GrayscaleParams &grayParams, - const OutlineParams &outlineParams) { - std::string shaderDir = ShaderManager::getInstance().getShaderDir(); - std::string shaderPath = shaderDir + "effects/grayscale_outline.shader"; - - Ptr shader = - ShaderManager::getInstance().loadFromCombinedFile(shaderPath); - if (!shader) { - E2D_LOG_ERROR("Failed to load grayscale_outline shader from: {}", - shaderPath); - return nullptr; - } - - shader->setFloat("u_grayIntensity", grayParams.intensity); - shader->setVec4("u_outlineColor", - glm::vec4(outlineParams.color.r, outlineParams.color.g, - outlineParams.color.b, outlineParams.color.a)); - shader->setFloat("u_thickness", outlineParams.thickness); - - return shader; -} - -/** - * @brief 创建像素化+反相组合效果着色器 - * @param pixParams 像素化效果参数 - * @param invParams 反相效果参数 - * @return 配置好的着色器 - */ -Ptr ShaderPreset::PixelateInvert(const PixelateParams &pixParams, - const InvertParams &invParams) { - std::string shaderDir = ShaderManager::getInstance().getShaderDir(); - std::string shaderPath = shaderDir + "effects/pixelate_invert.shader"; - - Ptr shader = - ShaderManager::getInstance().loadFromCombinedFile(shaderPath); - if (!shader) { - E2D_LOG_ERROR("Failed to load pixelate_invert shader from: {}", shaderPath); - return nullptr; - } - - shader->setFloat("u_pixelSize", pixParams.pixelSize); - shader->setFloat("u_invertStrength", invParams.strength); - - return shader; -} - -} // namespace extra2d diff --git a/Extra2D/src/graphics/texture_pool.cpp b/Extra2D/src/graphics/texture_pool.cpp index f5eb4dc..ea5b6c5 100644 --- a/Extra2D/src/graphics/texture_pool.cpp +++ b/Extra2D/src/graphics/texture_pool.cpp @@ -112,15 +112,10 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region, cacheMisses_.fetch_add(1, std::memory_order_relaxed); // 获取渲染后端 - RenderBackend* backend = nullptr; - if (scene_) { - // 假设 Scene 有获取 RenderBackend 的方法 - // 这里需要根据实际接口调整 - backend = nullptr; // TODO: 从 Scene 获取 RenderBackend - } + RenderBackend* backend = backend_; if (!backend) { - E2D_LOG_ERROR("TexturePool: RenderBackend not available"); + E2D_LOG_ERROR("TexturePool: RenderBackend not available, call setRenderBackend() first"); return TextureRef(); } 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(); -} - -}