2026-02-25 06:23:53 +08:00
|
|
|
#include <app/application.h>
|
2026-02-28 20:56:11 +08:00
|
|
|
#include <context/context.h>
|
2026-02-28 04:44:56 +08:00
|
|
|
#include <event/events.h>
|
2026-02-28 23:35:34 +08:00
|
|
|
#include <module/module_registry.h>
|
|
|
|
|
#include <platform/input_module.h>
|
|
|
|
|
#include <platform/window_module.h>
|
2026-02-25 06:23:53 +08:00
|
|
|
#include <utils/logger.h>
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
#include <SDL.h>
|
2026-02-11 19:40:26 +08:00
|
|
|
|
|
|
|
|
namespace extra2d {
|
|
|
|
|
|
2026-02-28 20:56:11 +08:00
|
|
|
std::unique_ptr<Application> Application::create() {
|
|
|
|
|
return std::unique_ptr<Application>(new Application());
|
2026-02-27 20:46:16 +08:00
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 20:56:11 +08:00
|
|
|
Application::Application() = default;
|
|
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
Application::~Application() { shutdown(); }
|
2026-02-28 20:56:11 +08:00
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
Application::Application(Application &&) noexcept = default;
|
|
|
|
|
Application &Application::operator=(Application &&) noexcept = default;
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
bool Application::init(const AppConfig &config) {
|
|
|
|
|
if (initialized_) {
|
|
|
|
|
E2D_LOG_WARN("Application already initialized");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
config_ = config;
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 20:56:11 +08:00
|
|
|
// 创建引擎上下文
|
|
|
|
|
context_ = Context::create();
|
|
|
|
|
if (!context_) {
|
|
|
|
|
E2D_LOG_ERROR("Failed to create context");
|
2026-02-27 23:08:49 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-28 20:56:11 +08:00
|
|
|
// 初始化引擎
|
|
|
|
|
if (!context_->init()) {
|
|
|
|
|
E2D_LOG_ERROR("Failed to initialize context");
|
2026-02-27 23:08:49 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
// 自动创建所有已注册的模块
|
|
|
|
|
initModules();
|
2026-02-28 22:30:48 +08:00
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
// 通过事件总线发送配置给所有监听模块
|
|
|
|
|
events::OnModuleConfig<AppConfig>::emit(config);
|
2026-02-28 22:30:48 +08:00
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
initialized_ = true;
|
|
|
|
|
running_ = true;
|
|
|
|
|
|
|
|
|
|
events::OnInit::emit();
|
|
|
|
|
|
|
|
|
|
E2D_LOG_INFO("Application initialized successfully");
|
2026-02-28 23:35:34 +08:00
|
|
|
E2D_LOG_INFO("Window: {}x{}, Fullscreen: {}, VSync: {}", config.width,
|
|
|
|
|
config.height, config.fullscreen, config.vsync);
|
2026-02-27 23:08:49 +08:00
|
|
|
return true;
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
void Application::initModules() {
|
|
|
|
|
// 从注册表自动创建所有模块
|
|
|
|
|
modules_ = ModuleRegistry::instance().createModules();
|
|
|
|
|
|
|
|
|
|
// 初始化所有模块
|
|
|
|
|
for (auto &module : modules_) {
|
|
|
|
|
if (!module->init()) {
|
|
|
|
|
E2D_LOG_ERROR("Failed to initialize module: {}", module->getName());
|
|
|
|
|
} else {
|
|
|
|
|
E2D_LOG_INFO("Module initialized: {} (priority: {})", module->getName(),
|
|
|
|
|
module->getPriority());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 19:40:26 +08:00
|
|
|
void Application::shutdown() {
|
2026-02-27 23:08:49 +08:00
|
|
|
if (!initialized_)
|
|
|
|
|
return;
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
events::OnShutdown::emit();
|
2026-02-27 22:59:17 +08:00
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
E2D_LOG_INFO("Shutting down application...");
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
// 按相反顺序销毁模块
|
|
|
|
|
for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) {
|
|
|
|
|
(*it)->shutdown();
|
|
|
|
|
}
|
|
|
|
|
modules_.clear();
|
2026-02-28 22:30:48 +08:00
|
|
|
|
|
|
|
|
// 关闭上下文
|
2026-02-28 20:56:11 +08:00
|
|
|
context_.reset();
|
|
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
initialized_ = false;
|
|
|
|
|
running_ = false;
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-27 23:08:49 +08:00
|
|
|
E2D_LOG_INFO("Application shutdown complete");
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::run() {
|
2026-02-27 23:08:49 +08:00
|
|
|
if (!initialized_) {
|
|
|
|
|
E2D_LOG_ERROR("Application not initialized");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
// 使用 SDL 的高精度计时器
|
|
|
|
|
Uint64 perfFreq = SDL_GetPerformanceFrequency();
|
|
|
|
|
Uint64 lastPerfCounter = SDL_GetPerformanceCounter();
|
|
|
|
|
|
|
|
|
|
WindowModule *window = getWindow();
|
|
|
|
|
InputModule *input = getInput();
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 20:56:11 +08:00
|
|
|
while (running_) {
|
2026-02-28 23:35:34 +08:00
|
|
|
// 处理窗口事件
|
|
|
|
|
if (window) {
|
|
|
|
|
if (!window->pollEvents()) {
|
|
|
|
|
quit();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算 deltaTime
|
|
|
|
|
Uint64 currentPerfCounter = SDL_GetPerformanceCounter();
|
|
|
|
|
deltaTime_ =
|
|
|
|
|
static_cast<float>(currentPerfCounter - lastPerfCounter) / perfFreq;
|
|
|
|
|
lastPerfCounter = currentPerfCounter;
|
|
|
|
|
|
|
|
|
|
totalTime_ += deltaTime_;
|
|
|
|
|
|
|
|
|
|
// 更新
|
|
|
|
|
if (!paused_) {
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 交换缓冲区
|
|
|
|
|
if (window) {
|
|
|
|
|
window->swapBuffers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FPS 限制 - 使用 SDL_Delay
|
|
|
|
|
if (!config_.vsync && config_.fpsLimit > 0) {
|
|
|
|
|
Uint64 frameEndCounter = SDL_GetPerformanceCounter();
|
|
|
|
|
float frameTime =
|
|
|
|
|
static_cast<float>(frameEndCounter - currentPerfCounter) / perfFreq;
|
|
|
|
|
float targetTime = 1.0f / config_.fpsLimit;
|
|
|
|
|
if (frameTime < targetTime) {
|
|
|
|
|
SDL_Delay(static_cast<Uint32>((targetTime - frameTime) * 1000));
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-27 23:08:49 +08:00
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::quit() {
|
2026-02-27 23:08:49 +08:00
|
|
|
shouldQuit_ = true;
|
|
|
|
|
running_ = false;
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::pause() {
|
2026-02-27 23:08:49 +08:00
|
|
|
if (!paused_) {
|
|
|
|
|
paused_ = true;
|
|
|
|
|
events::OnPause::emit();
|
|
|
|
|
E2D_LOG_INFO("Application paused");
|
|
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::resume() {
|
2026-02-27 23:08:49 +08:00
|
|
|
if (paused_) {
|
|
|
|
|
paused_ = false;
|
|
|
|
|
events::OnResume::emit();
|
|
|
|
|
E2D_LOG_INFO("Application resumed");
|
|
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
void Application::update() {
|
|
|
|
|
// 更新所有模块
|
|
|
|
|
for (auto &module : modules_) {
|
|
|
|
|
module->update(deltaTime_);
|
2026-02-27 23:08:49 +08:00
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
|
2026-02-28 20:56:11 +08:00
|
|
|
// 通过上下文更新引擎
|
|
|
|
|
if (context_) {
|
|
|
|
|
context_->tick(deltaTime_);
|
|
|
|
|
}
|
2026-02-11 19:40:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
WindowModule *Application::getWindow() const {
|
|
|
|
|
return getModule<WindowModule>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InputModule *Application::getInput() const { return getModule<InputModule>(); }
|
|
|
|
|
|
2026-02-28 22:30:48 +08:00
|
|
|
int32 Application::getWindowWidth() const {
|
2026-02-28 23:35:34 +08:00
|
|
|
if (WindowModule *window = getWindow()) {
|
|
|
|
|
Size size = window->getSize();
|
2026-02-28 22:30:48 +08:00
|
|
|
return static_cast<int32>(size.w);
|
|
|
|
|
}
|
|
|
|
|
return config_.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32 Application::getWindowHeight() const {
|
2026-02-28 23:35:34 +08:00
|
|
|
if (WindowModule *window = getWindow()) {
|
|
|
|
|
Size size = window->getSize();
|
2026-02-28 22:30:48 +08:00
|
|
|
return static_cast<int32>(size.h);
|
|
|
|
|
}
|
|
|
|
|
return config_.height;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-28 23:35:34 +08:00
|
|
|
const char *Application::getWindowTitle() const {
|
2026-02-28 22:30:48 +08:00
|
|
|
return config_.title.c_str();
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 19:40:26 +08:00
|
|
|
} // namespace extra2d
|