diff --git a/include/config/app_config.h b/include/config/app_config.h index 0d242c7..1a743a2 100644 --- a/include/config/app_config.h +++ b/include/config/app_config.h @@ -16,10 +16,7 @@ struct AppConfig { int32 height = 720; // 窗口高度 bool fullscreen = false; // 是否全屏 bool resizable = true; // 是否可调整大小 - bool vsync = true; // 是否垂直同步 int32 fpsLimit = 0; // FPS限制(0表示不限制) - int32 glMajor = 3; // OpenGL主版本 - int32 glMinor = 3; // OpenGL次版本 bool enableCursors = true; // 启用光标 bool enableDpiScale = false; // 启用DPI缩放 }; diff --git a/include/config/window_config.h b/include/config/window_config.h index 555d5cf..f7b0de5 100644 --- a/include/config/window_config.h +++ b/include/config/window_config.h @@ -11,14 +11,11 @@ namespace extra2d { * 专用于窗口模块的配置结构体 */ struct WindowCfg { - std::string title = "Extra2D"; // 窗口标题 - int32 width = 1280; // 窗口宽度 - int32 height = 720; // 窗口高度 - bool fullscreen = false; // 是否全屏 - bool resizable = true; // 是否可调整大小 - bool vsync = true; // 是否垂直同步 - int32 glMajor = 3; // OpenGL主版本 - int32 glMinor = 3; // OpenGL次版本 + std::string title = "Extra2D"; // 窗口标题 + int32 width = 1280; // 窗口宽度 + int32 height = 720; // 窗口高度 + bool fullscreen = false; // 是否全屏 + bool resizable = true; // 是否可调整大小 }; } // namespace extra2d diff --git a/include/context/context.h b/include/context/context.h index 4b320b9..306fd99 100644 --- a/include/context/context.h +++ b/include/context/context.h @@ -87,7 +87,6 @@ public: void stop() { running_ = false; } private: - std::unique_ptr moduleRegistry_; std::unique_ptr pluginLoader_; std::unique_ptr timerModule_; diff --git a/include/extra2d.h b/include/extra2d.h index 06f60f6..356dbd2 100644 --- a/include/extra2d.h +++ b/include/extra2d.h @@ -33,9 +33,6 @@ #include #include -// Platform -#include - // Utils #include #include @@ -47,13 +44,6 @@ // Application #include -// 兼容层 - 旧的头文件(将在后续版本中移除) -// #include // 已废弃,使用 Context -// #include // 已废弃,使用 imodule.h -// #include // 已废弃,使用 module_registry.h -// #include // 已废弃,使用 iplugin.h -// #include // 已废弃,使用 plugin_loader.h - #ifdef __SWITCH__ #include #endif diff --git a/include/platform/window_module.h b/include/platform/window_module.h index b1c40a5..d7fa297 100644 --- a/include/platform/window_module.h +++ b/include/platform/window_module.h @@ -3,10 +3,11 @@ #include #include #include +#include #include +#include #include #include -#include #include #include @@ -19,9 +20,9 @@ using ResizeCb = std::function; using CloseCb = std::function; /** - * @brief 窗口模块 - 简化版 + * @brief 窗口模块 - Vulkan 版本 * - * 管理 SDL2 窗口和 OpenGL 上下文 + * 管理 SDL2 窗口,支持 Vulkan 渲染 * 使用新的 Module 基类,支持自动注册 */ class WindowModule : public Module { @@ -55,21 +56,11 @@ public: */ bool pollEvents(); - /** - * @brief 交换缓冲区 - */ - void swapBuffers(); - /** * @brief 获取 SDL 窗口句柄 */ SDL_Window *handle() const { return window_; } - /** - * @brief 获取 OpenGL 上下文 - */ - SDL_GLContext glContext() const { return glCtx_; } - /** * @brief 获取窗口尺寸 */ @@ -100,16 +91,6 @@ public: */ bool isFullscreen() const; - /** - * @brief 设置垂直同步 - */ - void setVsync(bool vsync); - - /** - * @brief 检查是否垂直同步 - */ - bool isVsync() const; - /** * @brief 显示/隐藏窗口 */ @@ -140,42 +121,39 @@ public: */ bool shouldClose() const { return shouldClose_; } + /** + * @brief 获取 Vulkan 所需的窗口扩展 + * @return 扩展名称列表 + */ + std::vector getVulkanExtensions() const; + + /** + * @brief 创建 Vulkan 表面 + * @param instance Vulkan 实例 + * @param surface 输出的表面句柄 + * @return 是否成功 + */ + bool createVulkanSurface(void *instance, void **surface) const; + private: void handleWindowEvent(const SDL_WindowEvent &evt); /** * @brief 监听模块配置事件 - * @tparam ConfigT 配置类型 - * @param config 配置对象 + * @param config 应用配置对象 * - * 只处理 AppConfig 类型的配置 + * 处理 AppConfig 类型的配置,创建窗口 */ - template void onModuleConfig(const ConfigT &config) { - // 只处理 AppConfig 类型 - if constexpr (std::is_same_v) { - WindowCfg cfg; - cfg.title = config.title; - cfg.width = config.width; - cfg.height = config.height; - cfg.fullscreen = config.fullscreen; - cfg.resizable = config.resizable; - cfg.vsync = config.vsync; - cfg.glMajor = config.glMajor; - cfg.glMinor = config.glMinor; - - if (create(cfg)) { - setVisible(true); - } - } - } + void onModuleConfig(const AppConfig &config); SDL_Window *window_ = nullptr; - SDL_GLContext glCtx_ = nullptr; bool shouldClose_ = false; - bool vsync_ = true; CloseCb onClose_; ResizeCb onResize_; + + // 模块配置事件监听器 + std::unique_ptr::Listener> configListener_; }; } // namespace extra2d diff --git a/include/plugin/plugin_loader.h b/include/plugin/plugin_loader.h index aef72b1..a6af886 100644 --- a/include/plugin/plugin_loader.h +++ b/include/plugin/plugin_loader.h @@ -1,10 +1,9 @@ #pragma once #include -#include -#include #include -#include +#include +#include namespace extra2d { @@ -16,141 +15,141 @@ namespace extra2d { */ class PluginLoader { public: - PluginLoader(); - ~PluginLoader(); + PluginLoader(); + ~PluginLoader(); - // 禁止拷贝 - PluginLoader(const PluginLoader&) = delete; - PluginLoader& operator=(const PluginLoader&) = delete; + // 禁止拷贝 + PluginLoader(const PluginLoader &) = delete; + PluginLoader &operator=(const PluginLoader &) = delete; - // 允许移动 - PluginLoader(PluginLoader&&) noexcept; - PluginLoader& operator=(PluginLoader&&) noexcept; + // 允许移动 + PluginLoader(PluginLoader &&) noexcept; + PluginLoader &operator=(PluginLoader &&) noexcept; - /** - * @brief 从动态库加载插件 - * @param path 插件动态库路径 - * @return 是否加载成功 - */ - bool loadFromLibrary(const char* path); + /** + * @brief 从动态库加载插件 + * @param path 插件动态库路径 + * @return 是否加载成功 + */ + bool loadFromLibrary(const char *path); - /** - * @brief 注册内置插件(静态链接) - * @param plugin 插件实例指针(不由加载器管理生命周期) - */ - void registerPlugin(IPlugin* plugin); + /** + * @brief 注册内置插件(静态链接) + * @param plugin 插件实例指针(不由加载器管理生命周期) + */ + void registerPlugin(IPlugin *plugin); - /** - * @brief 卸载插件 - * @param name 插件名称 - */ - void unloadPlugin(const char* name); + /** + * @brief 卸载插件 + * @param name 插件名称 + */ + void unloadPlugin(const char *name); - /** - * @brief 获取插件 - * @param name 插件名称 - * @return 插件指针,不存在返回 nullptr - */ - IPlugin* getPlugin(const char* name) const; + /** + * @brief 获取插件 + * @param name 插件名称 + * @return 插件指针,不存在返回 nullptr + */ + IPlugin *getPlugin(const char *name) const; - /** - * @brief 检查插件是否存在 - * @param name 插件名称 - * @return 是否存在 - */ - bool hasPlugin(const char* name) const; + /** + * @brief 检查插件是否存在 + * @param name 插件名称 + * @return 是否存在 + */ + bool hasPlugin(const char *name) const; - /** - * @brief 获取所有插件 - * @return 插件列表 - */ - std::vector getAllPlugins() const; + /** + * @brief 获取所有插件 + * @return 插件列表 + */ + std::vector getAllPlugins() const; - /** - * @brief 初始化所有插件(自动处理依赖) - * @return 是否全部初始化成功 - */ - bool initAll(); + /** + * @brief 初始化所有插件(自动处理依赖) + * @return 是否全部初始化成功 + */ + bool initAll(); - /** - * @brief 关闭所有插件(按依赖逆序) - */ - void shutdownAll(); + /** + * @brief 关闭所有插件(按依赖逆序) + */ + void shutdownAll(); - /** - * @brief 获取插件数量 - * @return 插件数量 - */ - size_t getPluginCount() const; + /** + * @brief 获取插件数量 + * @return 插件数量 + */ + size_t getPluginCount() const; - /** - * @brief 添加插件搜索路径 - * @param path 搜索路径 - */ - void addSearchPath(const char* path); + /** + * @brief 添加插件搜索路径 + * @param path 搜索路径 + */ + void addSearchPath(const char *path); - /** - * @brief 从目录加载所有插件 - * @param directory 目录路径 - * @return 加载成功的插件数量 - */ - size_t loadPluginsFromDirectory(const char* directory); + /** + * @brief 从目录加载所有插件 + * @param directory 目录路径 + * @return 加载成功的插件数量 + */ + size_t loadPluginsFromDirectory(const char *directory); private: - /** - * @brief 插件条目结构 - */ - struct PluginEntry { - IPlugin* plugin = nullptr; // 插件实例 - void* handle = nullptr; // 动态库句柄 - bool isDynamic = false; // 是否为动态加载 - bool owned = false; // 是否由加载器管理生命周期 - }; + /** + * @brief 插件条目结构 + */ + struct PluginEntry { + IPlugin *plugin = nullptr; // 插件实例 + void *handle = nullptr; // 动态库句柄 + bool isDynamic = false; // 是否为动态加载 + bool owned = false; // 是否由加载器管理生命周期 + }; - /** - * @brief 解析插件依赖 - * @param plugin 插件 - * @return 依赖是否满足 - */ - bool resolveDependencies(IPlugin* plugin); + /** + * @brief 解析插件依赖 + * @param plugin 插件 + * @return 依赖是否满足 + */ + bool resolveDependencies(IPlugin *plugin); - /** - * @brief 检查依赖是否满足 - * @param dependencies 依赖列表 - * @return 是否满足 - */ - bool checkDependencies(const std::vector& dependencies); + /** + * @brief 检查依赖是否满足 + * @param dependencies 依赖列表 + * @return 是否满足 + */ + bool checkDependencies(const std::vector &dependencies); - /** - * @brief 按依赖顺序排序插件 - */ - void sortPluginsByDependencies(); + /** + * @brief 按依赖顺序排序插件 + */ + void sortPluginsByDependencies(); - /** - * @brief 加载动态库 - * @param path 库路径 - * @return 库句柄 - */ - void* loadDynamicLibrary(const char* path); + /** + * @brief 加载动态库 + * @param path 库路径 + * @return 库句柄 + */ + void *loadDynamicLibrary(const char *path); - /** - * @brief 卸载动态库 - * @param handle 库句柄 - */ - void unloadDynamicLibrary(void* handle); + /** + * @brief 卸载动态库 + * @param handle 库句柄 + */ + void unloadDynamicLibrary(void *handle); - /** - * @brief 获取动态库符号 - * @param handle 库句柄 - * @param name 符号名称 - * @return 符号地址 - */ - void* getSymbol(void* handle, const char* name); + /** + * @brief 获取动态库符号 + * @param handle 库句柄 + * @param name 符号名称 + * @return 符号地址 + */ + void *getSymbol(void *handle, const char *name); - std::unordered_map plugins_; - std::vector searchPaths_; - std::vector sortedPlugins_; // 按依赖排序的插件列表 - bool inited_ = false; + std::unordered_map plugins_; + std::vector searchPaths_; + std::vector sortedPlugins_; // 按依赖排序的插件列表 + bool inited_ = false; }; } // namespace extra2d diff --git a/src/app/application.cpp b/src/app/application.cpp index 459e5a5..1b3d2b1 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -54,8 +54,8 @@ bool Application::init(const AppConfig &config) { events::OnInit::emit(); E2D_LOG_INFO("Application initialized successfully"); - E2D_LOG_INFO("Window: {}x{}, Fullscreen: {}, VSync: {}", config.width, - config.height, config.fullscreen, config.vsync); + E2D_LOG_INFO("Window: {}x{}, Fullscreen: {}", config.width, + config.height, config.fullscreen); return true; } @@ -132,13 +132,8 @@ void Application::run() { update(); } - // 交换缓冲区 - if (window) { - window->swapBuffers(); - } - // FPS 限制 - 使用 SDL_Delay - if (!config_.vsync && config_.fpsLimit > 0) { + if (config_.fpsLimit > 0) { Uint64 frameEndCounter = SDL_GetPerformanceCounter(); float frameTime = static_cast(frameEndCounter - currentPerfCounter) / perfFreq; diff --git a/src/context/context.cpp b/src/context/context.cpp index 0d04e85..db45e08 100644 --- a/src/context/context.cpp +++ b/src/context/context.cpp @@ -1,106 +1,93 @@ #include -#include -#include -#include #include -#include +#include +#include +#include namespace extra2d { Context::Context() - : moduleRegistry_(std::make_unique()) - , pluginLoader_(std::make_unique()) - , timerModule_(std::make_unique()) -{ -} + : pluginLoader_(std::make_unique()), + timerModule_(std::make_unique()) {} Context::~Context() { - if (inited_) { - shutdown(); - } + if (inited_) { + shutdown(); + } } -Context::Context(Context&&) noexcept = default; -Context& Context::operator=(Context&&) noexcept = default; +Context::Context(Context &&) noexcept = default; +Context &Context::operator=(Context &&) noexcept = default; std::unique_ptr Context::create() { - return std::make_unique(); + return std::make_unique(); } bool Context::init() { - if (inited_) { - return true; - } - - // 发送引擎初始化事件 - events::OnInit::emit(); - - // 注册核心模块 - moduleRegistry_->registerModule(timerModule_.get()); - - // 初始化所有模块 - if (!moduleRegistry_->initAll()) { - return false; - } - - // 初始化所有插件 - if (!pluginLoader_->initAll()) { - return false; - } - - inited_ = true; - running_ = true; + if (inited_) { return true; + } + + // 发送引擎初始化事件 + events::OnInit::emit(); + + // 初始化定时器模块 + if (!timerModule_->init()) { + return false; + } + + // 初始化所有插件 + if (!pluginLoader_->initAll()) { + return false; + } + + inited_ = true; + running_ = true; + return true; } void Context::shutdown() { - if (!inited_) { - return; - } + if (!inited_) { + return; + } - running_ = false; + running_ = false; - // 关闭所有插件 - pluginLoader_->shutdownAll(); + // 关闭所有插件 + pluginLoader_->shutdownAll(); - // 关闭所有模块 - moduleRegistry_->shutdownAll(); + // 关闭定时器模块 + timerModule_->shutdown(); - // 发送引擎关闭事件 - events::OnShutdown::emit(); + // 发送引擎关闭事件 + events::OnShutdown::emit(); - inited_ = false; + inited_ = false; } void Context::tick(float dt) { - if (!running_) { - return; - } + if (!running_) { + return; + } - // 更新时间和帧数 - totalTime_ += dt; - frameCount_++; + // 更新时间和帧数 + totalTime_ += dt; + frameCount_++; - // 更新定时器模块 - timerModule_->update(dt); + // 更新定时器模块 + timerModule_->update(dt); - // 发送更新事件 - events::OnUpdate::emit(dt); + // 发送更新事件 + events::OnUpdate::emit(dt); - // 发送延迟更新事件 - events::OnLateUpdate::emit(dt); + // 发送延迟更新事件 + events::OnLateUpdate::emit(dt); } -ModuleRegistry& Context::modules() { - return *moduleRegistry_; -} +ModuleRegistry &Context::modules() { return ModuleRegistry::instance(); } -PluginLoader& Context::plugins() { - return *pluginLoader_; -} +PluginLoader &Context::plugins() { return *pluginLoader_; } -TimerModule& Context::timer() { - return *timerModule_; -} +TimerModule &Context::timer() { return *timerModule_; } } // namespace extra2d diff --git a/src/module/timer_module.cpp b/src/module/timer_module.cpp deleted file mode 100644 index 9dd67c7..0000000 --- a/src/module/timer_module.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include - -namespace extra2d { - -TimerModule::TimerModule() = default; - -TimerModule::~TimerModule() { - shutdown(); -} - -TimerModule::TimerModule(TimerModule&& other) noexcept - : timers_(std::move(other.timers_)) - , pendingRemove_(std::move(other.pendingRemove_)) - , nextId_(other.nextId_) - , timeScale_(other.timeScale_) - , inUpdate_(other.inUpdate_) { -} - -TimerModule& TimerModule::operator=(TimerModule&& other) noexcept { - if (this != &other) { - shutdown(); - - timers_ = std::move(other.timers_); - pendingRemove_ = std::move(other.pendingRemove_); - nextId_ = other.nextId_; - timeScale_ = other.timeScale_; - inUpdate_ = other.inUpdate_; - } - return *this; -} - -bool TimerModule::init() { - // 初始化完成,等待 OnUpdate 事件 - return true; -} - -void TimerModule::shutdown() { - cancelAll(); -} - -TimerId TimerModule::scheduleOnce(float delay, TimerCallback callback) { - if (delay < 0.0f) delay = 0.0f; - - TimerId id = generateId(); - auto info = std::make_unique(); - info->id = id; - info->interval = delay; - info->elapsed = 0.0f; - info->repeat = 1; - info->executed = 0; - info->paused = false; - info->cancelled = false; - info->callback = std::move(callback); - - timers_[id] = std::move(info); - return id; -} - -TimerId TimerModule::scheduleRepeat(float interval, uint32 repeat, TimerCallback callback) { - if (interval < 0.0f) interval = 0.0f; - - TimerId id = generateId(); - auto info = std::make_unique(); - info->id = id; - info->interval = interval; - info->elapsed = 0.0f; - info->repeat = repeat; - info->executed = 0; - info->paused = false; - info->cancelled = false; - info->callback = std::move(callback); - - timers_[id] = std::move(info); - return id; -} - -TimerId TimerModule::scheduleUpdate(TimerUpdateCallback callback) { - TimerId id = generateId(); - auto info = std::make_unique(); - info->id = id; - info->interval = 0.0f; - info->elapsed = 0.0f; - info->repeat = 0; - info->executed = 0; - info->paused = false; - info->cancelled = false; - info->updateCallback = std::move(callback); - - timers_[id] = std::move(info); - return id; -} - -void TimerModule::cancel(TimerId id) { - if (id == INVALID_TIMER_ID) return; - - auto it = timers_.find(id); - if (it != timers_.end()) { - if (inUpdate_) { - // 如果在更新中,标记为待删除 - it->second->cancelled = true; - pendingRemove_.push_back(id); - } else { - // 直接删除 - timers_.erase(it); - } - } -} - -void TimerModule::pause(TimerId id) { - if (id == INVALID_TIMER_ID) return; - - auto it = timers_.find(id); - if (it != timers_.end()) { - it->second->paused = true; - } -} - -void TimerModule::resume(TimerId id) { - if (id == INVALID_TIMER_ID) return; - - auto it = timers_.find(id); - if (it != timers_.end()) { - it->second->paused = false; - } -} - -void TimerModule::cancelAll() { - if (inUpdate_) { - // 如果在更新中,标记所有为待删除 - for (auto& pair : timers_) { - pair.second->cancelled = true; - pendingRemove_.push_back(pair.first); - } - } else { - // 直接清空 - timers_.clear(); - } -} - -size_t TimerModule::getActiveCount() const { - size_t count = 0; - for (const auto& pair : timers_) { - if (!pair.second->cancelled) { - ++count; - } - } - return count; -} - -void TimerModule::update(float dt) { - if (timers_.empty()) return; - - // 应用时间缩放 - dt *= timeScale_; - - inUpdate_ = true; - - // 收集需要执行的定时器 - std::vector toExecute; - std::vector toRemove; - - for (auto& pair : timers_) { - TimerInfo* info = pair.second.get(); - - if (info->cancelled || info->paused) { - continue; - } - - // 更新任务(每帧执行) - if (info->updateCallback) { - toExecute.push_back(info); - continue; - } - - // 定时任务 - info->elapsed += dt; - - if (info->elapsed >= info->interval) { - toExecute.push_back(info); - - // 重置计时器 - info->elapsed = 0.0f; - info->executed++; - - // 检查是否需要移除 - if (info->repeat > 0 && info->executed >= info->repeat) { - toRemove.push_back(info->id); - } - } - } - - // 执行回调 - for (TimerInfo* info : toExecute) { - if (info->callback) { - info->callback(); - } - if (info->updateCallback) { - info->updateCallback(dt); - } - } - - inUpdate_ = false; - - // 移除已完成的定时器 - for (TimerId id : toRemove) { - timers_.erase(id); - } - - // 处理待删除列表 - for (TimerId id : pendingRemove_) { - timers_.erase(id); - } - pendingRemove_.clear(); -} - -TimerId TimerModule::generateId() { - return nextId_++; -} - -} // namespace extra2d diff --git a/src/platform/window_module.cpp b/src/platform/window_module.cpp index 2a7b573..2349a44 100644 --- a/src/platform/window_module.cpp +++ b/src/platform/window_module.cpp @@ -1,9 +1,15 @@ #include -#include #include #include +#include #include +// SDL Vulkan support +#include + +// Vulkan +#include + namespace extra2d { WindowModule::WindowModule() = default; @@ -14,53 +20,42 @@ WindowModule::~WindowModule() { WindowModule::WindowModule(WindowModule&& other) noexcept : window_(other.window_) - , glCtx_(other.glCtx_) , shouldClose_(other.shouldClose_) - , vsync_(other.vsync_) , onClose_(std::move(other.onClose_)) - , onResize_(std::move(other.onResize_)) { + , onResize_(std::move(other.onResize_)) + , configListener_(std::move(other.configListener_)) { other.window_ = nullptr; - other.glCtx_ = nullptr; } WindowModule& WindowModule::operator=(WindowModule&& other) noexcept { if (this != &other) { shutdown(); window_ = other.window_; - glCtx_ = other.glCtx_; shouldClose_ = other.shouldClose_; - vsync_ = other.vsync_; onClose_ = std::move(other.onClose_); onResize_ = std::move(other.onResize_); + configListener_ = std::move(other.configListener_); other.window_ = nullptr; - other.glCtx_ = nullptr; } return *this; } bool WindowModule::init() { - if (!Sdl2::initVideo()) { + if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { + E2D_LOG_ERROR("Failed to initialize SDL video: {}", SDL_GetError()); return false; } - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - // 监听模块配置事件 - events::OnModuleConfig::subscribe(this, &WindowModule::onModuleConfig); + configListener_ = std::make_unique::Listener>(); + configListener_->bind([this](const AppConfig& config) { + this->onModuleConfig(config); + }); return true; } void WindowModule::shutdown() { - if (glCtx_) { - SDL_GL_DeleteContext(glCtx_); - glCtx_ = nullptr; - } if (window_) { SDL_DestroyWindow(window_); window_ = nullptr; @@ -71,7 +66,7 @@ bool WindowModule::create(const WindowCfg& cfg) { if (window_) return true; - uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; + uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN; if (cfg.resizable) { flags |= SDL_WINDOW_RESIZABLE; } @@ -79,9 +74,6 @@ bool WindowModule::create(const WindowCfg& cfg) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, cfg.glMajor); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, cfg.glMinor); - window_ = SDL_CreateWindow(cfg.title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, cfg.width, cfg.height, flags); @@ -90,20 +82,10 @@ bool WindowModule::create(const WindowCfg& cfg) { return false; } - glCtx_ = SDL_GL_CreateContext(window_); - if (!glCtx_) { - E2D_LOG_ERROR("Failed to create OpenGL context: {}", SDL_GetError()); - SDL_DestroyWindow(window_); - window_ = nullptr; - return false; - } - - setVsync(cfg.vsync); - vsync_ = cfg.vsync; - // 发送窗口显示事件 events::OnShow::emit(); + E2D_LOG_INFO("Window created: {}x{}", cfg.width, cfg.height); return true; } @@ -164,9 +146,16 @@ void WindowModule::handleWindowEvent(const SDL_WindowEvent& evt) { } } -void WindowModule::swapBuffers() { - if (window_ && glCtx_) { - SDL_GL_SwapWindow(window_); +void WindowModule::onModuleConfig(const AppConfig &config) { + WindowCfg cfg; + cfg.title = config.title; + cfg.width = config.width; + cfg.height = config.height; + cfg.fullscreen = config.fullscreen; + cfg.resizable = config.resizable; + + if (create(cfg)) { + setVisible(true); } } @@ -212,15 +201,6 @@ bool WindowModule::isFullscreen() const { return (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; } -void WindowModule::setVsync(bool vsync) { - SDL_GL_SetSwapInterval(vsync ? 1 : 0); - vsync_ = vsync; -} - -bool WindowModule::isVsync() const { - return vsync_; -} - void WindowModule::setVisible(bool visible) { if (window_) { if (visible) { @@ -242,4 +222,25 @@ bool WindowModule::isVisible() const { return (flags & SDL_WINDOW_SHOWN) != 0; } +std::vector WindowModule::getVulkanExtensions() const { + std::vector extensions; + if (!window_) { + return extensions; + } + + uint32 count = 0; + SDL_Vulkan_GetInstanceExtensions(window_, &count, nullptr); + extensions.resize(count); + SDL_Vulkan_GetInstanceExtensions(window_, &count, extensions.data()); + + return extensions; +} + +bool WindowModule::createVulkanSurface(void* instance, void** surface) const { + if (!window_ || !instance || !surface) { + return false; + } + return SDL_Vulkan_CreateSurface(window_, static_cast(instance), reinterpret_cast(surface)); +} + } // namespace extra2d diff --git a/src/utils/timer_module.cpp b/src/utils/timer_module.cpp new file mode 100644 index 0000000..4fa998c --- /dev/null +++ b/src/utils/timer_module.cpp @@ -0,0 +1,219 @@ +#include +#include + +namespace extra2d { + +TimerModule::TimerModule() = default; + +TimerModule::~TimerModule() { shutdown(); } + +TimerModule::TimerModule(TimerModule &&other) noexcept + : timers_(std::move(other.timers_)), + pendingRemove_(std::move(other.pendingRemove_)), nextId_(other.nextId_), + timeScale_(other.timeScale_), inUpdate_(other.inUpdate_) {} + +TimerModule &TimerModule::operator=(TimerModule &&other) noexcept { + if (this != &other) { + shutdown(); + + timers_ = std::move(other.timers_); + pendingRemove_ = std::move(other.pendingRemove_); + nextId_ = other.nextId_; + timeScale_ = other.timeScale_; + inUpdate_ = other.inUpdate_; + } + return *this; +} + +bool TimerModule::init() { + // 初始化完成,等待 OnUpdate 事件 + return true; +} + +void TimerModule::shutdown() { cancelAll(); } + +TimerId TimerModule::scheduleOnce(float delay, TimerCallback callback) { + if (delay < 0.0f) + delay = 0.0f; + + TimerId id = generateId(); + auto info = std::make_unique(); + info->id = id; + info->interval = delay; + info->elapsed = 0.0f; + info->repeat = 1; + info->executed = 0; + info->paused = false; + info->cancelled = false; + info->callback = std::move(callback); + + timers_[id] = std::move(info); + return id; +} + +TimerId TimerModule::scheduleRepeat(float interval, uint32 repeat, + TimerCallback callback) { + if (interval < 0.0f) + interval = 0.0f; + + TimerId id = generateId(); + auto info = std::make_unique(); + info->id = id; + info->interval = interval; + info->elapsed = 0.0f; + info->repeat = repeat; + info->executed = 0; + info->paused = false; + info->cancelled = false; + info->callback = std::move(callback); + + timers_[id] = std::move(info); + return id; +} + +TimerId TimerModule::scheduleUpdate(TimerUpdateCallback callback) { + TimerId id = generateId(); + auto info = std::make_unique(); + info->id = id; + info->interval = 0.0f; + info->elapsed = 0.0f; + info->repeat = 0; + info->executed = 0; + info->paused = false; + info->cancelled = false; + info->updateCallback = std::move(callback); + + timers_[id] = std::move(info); + return id; +} + +void TimerModule::cancel(TimerId id) { + if (id == INVALID_TIMER_ID) + return; + + auto it = timers_.find(id); + if (it != timers_.end()) { + if (inUpdate_) { + // 如果在更新中,标记为待删除 + it->second->cancelled = true; + pendingRemove_.push_back(id); + } else { + // 直接删除 + timers_.erase(it); + } + } +} + +void TimerModule::pause(TimerId id) { + if (id == INVALID_TIMER_ID) + return; + + auto it = timers_.find(id); + if (it != timers_.end()) { + it->second->paused = true; + } +} + +void TimerModule::resume(TimerId id) { + if (id == INVALID_TIMER_ID) + return; + + auto it = timers_.find(id); + if (it != timers_.end()) { + it->second->paused = false; + } +} + +void TimerModule::cancelAll() { + if (inUpdate_) { + // 如果在更新中,标记所有为待删除 + for (auto &pair : timers_) { + pair.second->cancelled = true; + pendingRemove_.push_back(pair.first); + } + } else { + // 直接清空 + timers_.clear(); + } +} + +size_t TimerModule::getActiveCount() const { + size_t count = 0; + for (const auto &pair : timers_) { + if (!pair.second->cancelled) { + ++count; + } + } + return count; +} + +void TimerModule::update(float dt) { + if (timers_.empty()) + return; + + // 应用时间缩放 + dt *= timeScale_; + + inUpdate_ = true; + + // 收集需要执行的定时器 + std::vector toExecute; + std::vector toRemove; + + for (auto &pair : timers_) { + TimerInfo *info = pair.second.get(); + + if (info->cancelled || info->paused) { + continue; + } + + // 更新任务(每帧执行) + if (info->updateCallback) { + toExecute.push_back(info); + continue; + } + + // 定时任务 + info->elapsed += dt; + + if (info->elapsed >= info->interval) { + toExecute.push_back(info); + + // 重置计时器 + info->elapsed = 0.0f; + info->executed++; + + // 检查是否需要移除 + if (info->repeat > 0 && info->executed >= info->repeat) { + toRemove.push_back(info->id); + } + } + } + + // 执行回调 + for (TimerInfo *info : toExecute) { + if (info->callback) { + info->callback(); + } + if (info->updateCallback) { + info->updateCallback(dt); + } + } + + inUpdate_ = false; + + // 移除已完成的定时器 + for (TimerId id : toRemove) { + timers_.erase(id); + } + + // 处理待删除列表 + for (TimerId id : pendingRemove_) { + timers_.erase(id); + } + pendingRemove_.clear(); +} + +TimerId TimerModule::generateId() { return nextId_++; } + +} // namespace extra2d diff --git a/xmake.lua b/xmake.lua index 0c159db..007707b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -78,7 +78,7 @@ end -- ============================================== if target_plat == "mingw" then - add_requires("glm", "libsdl2", "libsdl2_mixer") + add_requires("glm", "libsdl2", "libsdl2_mixer", "vulkansdk") end -- ============================================== diff --git a/xmake/engine.lua b/xmake/engine.lua index f6ffd61..7b72d9b 100644 --- a/xmake/engine.lua +++ b/xmake/engine.lua @@ -14,23 +14,23 @@ function define_extra2d_engine() set_kind("static") add_files("src/**.cpp|core/*.cpp|module/module_manager.cpp|plugin/plugin_manager.cpp|platform/window.cpp|platform/input.cpp") - add_files("third_party/glad/src/glad.c") add_includedirs("include", {public = true}) - add_includedirs("third_party/glad/include", {public = true}) add_includedirs("third_party", {public = true}) local plat = get_current_plat() if plat == "mingw" then add_defines("_UNICODE", "UNICODE") - add_packages("glm", "libsdl2", "libsdl2_mixer", {public = true}) - add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi", {public = true}) + -- 使用 xmake 官方包 + add_packages("glm", "libsdl2", "libsdl2_mixer", "vulkansdk", {public = true}) + add_syslinks("winmm", "imm32", "version", "setupapi", {public = true}) elseif plat == "switch" then local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro" add_includedirs(devkitPro .. "/portlibs/switch/include", {public = true}) add_linkdirs(devkitPro .. "/portlibs/switch/lib") + -- Switch 平台可能需要不同的图形库 add_syslinks("SDL2_mixer", "SDL2", "opusfile", "opus", "vorbisidec", "ogg", - "modplug", "mpg123", "FLAC", "GLESv2", "EGL", "glapi", "drm_nouveau", + "modplug", "mpg123", "FLAC", "drm_nouveau", {public = true}) end