feat: 添加SDL2后端支持并实现基础示例程序
添加SDL2作为平台后端支持,包括窗口创建、输入处理和GLAD初始化 实现基础示例程序展示引擎基本功能 重构平台配置代码以提高可读性 移除未使用的input_codes.h头文件 添加demo_basic构建目标到xmake配置
This commit is contained in:
parent
34fe0bafcb
commit
38148a6c54
|
|
@ -48,7 +48,6 @@
|
|||
#include <extra2d/event/event.h>
|
||||
#include <extra2d/event/event_dispatcher.h>
|
||||
#include <extra2d/event/event_queue.h>
|
||||
#include <extra2d/event/input_codes.h>
|
||||
|
||||
// Utils
|
||||
#include <extra2d/utils/logger.h>
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ private:
|
|||
*/
|
||||
#define E2D_REG_BACKEND(name, WinClass, InClass) \
|
||||
namespace { \
|
||||
__attribute__((used)) \
|
||||
static struct E2D_BACKEND_REG_##name { \
|
||||
E2D_BACKEND_REG_##name() { \
|
||||
::extra2d::BackendFactory::reg( \
|
||||
|
|
|
|||
|
|
@ -16,10 +16,18 @@
|
|||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
|
||||
#ifdef E2D_BACKEND_SDL2
|
||||
namespace extra2d {
|
||||
void initSDL2Backend();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
|
|
@ -56,10 +64,16 @@ bool Application::init() {
|
|||
|
||||
bool Application::init(const AppConfig& config) {
|
||||
if (initialized_) {
|
||||
E2D_LOG_WARN("Application already initialized");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0) {
|
||||
E2D_LOG_ERROR("Failed to initialize SDL: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::init();
|
||||
|
||||
E2D_LOG_INFO("Initializing application with config...");
|
||||
|
||||
if (!ConfigManager::instance().initialize()) {
|
||||
|
|
@ -92,6 +106,10 @@ bool Application::init(const std::string& configPath) {
|
|||
}
|
||||
|
||||
bool Application::initImpl() {
|
||||
#ifdef E2D_BACKEND_SDL2
|
||||
initSDL2Backend();
|
||||
#endif
|
||||
|
||||
auto& configMgr = ConfigManager::instance();
|
||||
AppConfig& appConfig = configMgr.appConfig();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include <extra2d/config/platform_config.h>
|
||||
#include <extra2d/config/app_config.h>
|
||||
#include <extra2d/config/platform_config.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -39,24 +39,28 @@ public:
|
|||
}
|
||||
|
||||
PlatformType platformType() const override { return PlatformType::Windows; }
|
||||
const char* platformName() const override { return "Windows"; }
|
||||
const PlatformCapabilities& capabilities() const override { return caps_; }
|
||||
const char *platformName() const override { return "Windows"; }
|
||||
const PlatformCapabilities &capabilities() const override { return caps_; }
|
||||
|
||||
void applyConstraints(AppConfig& config) const override {
|
||||
if (config.window.width < 320) config.window.width = 320;
|
||||
if (config.window.height < 240) config.window.height = 240;
|
||||
if (config.window.width > caps_.maxTextureSize) config.window.width = caps_.maxTextureSize;
|
||||
if (config.window.height > caps_.maxTextureSize) config.window.height = caps_.maxTextureSize;
|
||||
void applyConstraints(AppConfig &config) const override {
|
||||
if (config.window.width < 320)
|
||||
config.window.width = 320;
|
||||
if (config.window.height < 240)
|
||||
config.window.height = 240;
|
||||
if (config.window.width > caps_.maxTextureSize)
|
||||
config.window.width = caps_.maxTextureSize;
|
||||
if (config.window.height > caps_.maxTextureSize)
|
||||
config.window.height = caps_.maxTextureSize;
|
||||
}
|
||||
|
||||
void applyDefaults(AppConfig& config) const override {
|
||||
void applyDefaults(AppConfig &config) const override {
|
||||
config.window.highDPI = true;
|
||||
config.window.resizable = true;
|
||||
config.render.vsync = true;
|
||||
config.render.targetFPS = 60;
|
||||
}
|
||||
|
||||
bool validateConfig(AppConfig& config) const override {
|
||||
bool validateConfig(AppConfig &config) const override {
|
||||
if (config.window.width <= 0 || config.window.height <= 0) {
|
||||
E2D_LOG_ERROR("Windows: Invalid window dimensions");
|
||||
return false;
|
||||
|
|
@ -67,8 +71,8 @@ public:
|
|||
int getRecommendedWidth() const override { return 1920; }
|
||||
int getRecommendedHeight() const override { return 1080; }
|
||||
bool isResolutionSupported(int width, int height) const override {
|
||||
return width >= 320 && height >= 240 &&
|
||||
width <= caps_.maxTextureSize && height <= caps_.maxTextureSize;
|
||||
return width >= 320 && height >= 240 && width <= caps_.maxTextureSize &&
|
||||
height <= caps_.maxTextureSize;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -100,20 +104,22 @@ public:
|
|||
}
|
||||
|
||||
PlatformType platformType() const override { return PlatformType::Linux; }
|
||||
const char* platformName() const override { return "Linux"; }
|
||||
const PlatformCapabilities& capabilities() const override { return caps_; }
|
||||
const char *platformName() const override { return "Linux"; }
|
||||
const PlatformCapabilities &capabilities() const override { return caps_; }
|
||||
|
||||
void applyConstraints(AppConfig& config) const override {
|
||||
if (config.window.width < 320) config.window.width = 320;
|
||||
if (config.window.height < 240) config.window.height = 240;
|
||||
void applyConstraints(AppConfig &config) const override {
|
||||
if (config.window.width < 320)
|
||||
config.window.width = 320;
|
||||
if (config.window.height < 240)
|
||||
config.window.height = 240;
|
||||
}
|
||||
|
||||
void applyDefaults(AppConfig& config) const override {
|
||||
void applyDefaults(AppConfig &config) const override {
|
||||
config.window.resizable = true;
|
||||
config.render.vsync = true;
|
||||
}
|
||||
|
||||
bool validateConfig(AppConfig& config) const override {
|
||||
bool validateConfig(AppConfig &config) const override {
|
||||
if (config.window.width <= 0 || config.window.height <= 0) {
|
||||
E2D_LOG_ERROR("Linux: Invalid window dimensions");
|
||||
return false;
|
||||
|
|
@ -156,21 +162,23 @@ public:
|
|||
}
|
||||
|
||||
PlatformType platformType() const override { return PlatformType::macOS; }
|
||||
const char* platformName() const override { return "macOS"; }
|
||||
const PlatformCapabilities& capabilities() const override { return caps_; }
|
||||
const char *platformName() const override { return "macOS"; }
|
||||
const PlatformCapabilities &capabilities() const override { return caps_; }
|
||||
|
||||
void applyConstraints(AppConfig& config) const override {
|
||||
if (config.window.width < 320) config.window.width = 320;
|
||||
if (config.window.height < 240) config.window.height = 240;
|
||||
void applyConstraints(AppConfig &config) const override {
|
||||
if (config.window.width < 320)
|
||||
config.window.width = 320;
|
||||
if (config.window.height < 240)
|
||||
config.window.height = 240;
|
||||
}
|
||||
|
||||
void applyDefaults(AppConfig& config) const override {
|
||||
void applyDefaults(AppConfig &config) const override {
|
||||
config.window.highDPI = true;
|
||||
config.window.resizable = true;
|
||||
config.render.vsync = true;
|
||||
}
|
||||
|
||||
bool validateConfig(AppConfig& config) const override {
|
||||
bool validateConfig(AppConfig &config) const override {
|
||||
if (config.window.width <= 0 || config.window.height <= 0) {
|
||||
E2D_LOG_ERROR("macOS: Invalid window dimensions");
|
||||
return false;
|
||||
|
|
@ -214,10 +222,10 @@ public:
|
|||
}
|
||||
|
||||
PlatformType platformType() const override { return PlatformType::Switch; }
|
||||
const char* platformName() const override { return "Nintendo Switch"; }
|
||||
const PlatformCapabilities& capabilities() const override { return caps_; }
|
||||
const char *platformName() const override { return "Nintendo Switch"; }
|
||||
const PlatformCapabilities &capabilities() const override { return caps_; }
|
||||
|
||||
void applyConstraints(AppConfig& config) const override {
|
||||
void applyConstraints(AppConfig &config) const override {
|
||||
config.window.width = 1920;
|
||||
config.window.height = 1080;
|
||||
config.window.mode = WindowMode::Fullscreen;
|
||||
|
|
@ -230,7 +238,7 @@ public:
|
|||
config.input.maxGamepads = 2;
|
||||
}
|
||||
|
||||
void applyDefaults(AppConfig& config) const override {
|
||||
void applyDefaults(AppConfig &config) const override {
|
||||
config.window.width = 1920;
|
||||
config.window.height = 1080;
|
||||
config.window.mode = WindowMode::Fullscreen;
|
||||
|
|
@ -240,7 +248,7 @@ public:
|
|||
config.input.enableVibration = true;
|
||||
}
|
||||
|
||||
bool validateConfig(AppConfig& config) const override {
|
||||
bool validateConfig(AppConfig &config) const override {
|
||||
if (config.window.mode != WindowMode::Fullscreen) {
|
||||
E2D_LOG_WARN("Switch: Only fullscreen mode is supported");
|
||||
config.window.mode = WindowMode::Fullscreen;
|
||||
|
|
@ -284,10 +292,10 @@ public:
|
|||
}
|
||||
|
||||
PlatformType platformType() const override { return PlatformType::Switch; }
|
||||
const char* platformName() const override { return "Nintendo Switch"; }
|
||||
const PlatformCapabilities& capabilities() const override { return caps_; }
|
||||
const char *platformName() const override { return "Nintendo Switch"; }
|
||||
const PlatformCapabilities &capabilities() const override { return caps_; }
|
||||
|
||||
void applyConstraints(AppConfig& config) const override {
|
||||
void applyConstraints(AppConfig &config) const override {
|
||||
config.window.width = 1920;
|
||||
config.window.height = 1080;
|
||||
config.window.mode = WindowMode::Fullscreen;
|
||||
|
|
@ -300,7 +308,7 @@ public:
|
|||
config.input.maxGamepads = 2;
|
||||
}
|
||||
|
||||
void applyDefaults(AppConfig& config) const override {
|
||||
void applyDefaults(AppConfig &config) const override {
|
||||
config.window.width = 1920;
|
||||
config.window.height = 1080;
|
||||
config.window.mode = WindowMode::Fullscreen;
|
||||
|
|
@ -310,7 +318,7 @@ public:
|
|||
config.input.enableVibration = true;
|
||||
}
|
||||
|
||||
bool validateConfig(AppConfig& config) const override {
|
||||
bool validateConfig(AppConfig &config) const override {
|
||||
if (config.window.mode != WindowMode::Fullscreen) {
|
||||
E2D_LOG_WARN("Switch: Only fullscreen mode is supported");
|
||||
}
|
||||
|
|
@ -329,7 +337,7 @@ private:
|
|||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief 创建平台配置实例
|
||||
|
|
@ -377,15 +385,21 @@ UniquePtr<PlatformConfig> createPlatformConfig(PlatformType type) {
|
|||
* @param type 平台类型枚举值
|
||||
* @return 平台名称字符串
|
||||
*/
|
||||
const char* getPlatformTypeName(PlatformType type) {
|
||||
const char *getPlatformTypeName(PlatformType type) {
|
||||
switch (type) {
|
||||
case PlatformType::Auto: return "Auto";
|
||||
case PlatformType::Windows: return "Windows";
|
||||
case PlatformType::Switch: return "Switch";
|
||||
case PlatformType::Linux: return "Linux";
|
||||
case PlatformType::macOS: return "macOS";
|
||||
default: return "Unknown";
|
||||
case PlatformType::Auto:
|
||||
return "Auto";
|
||||
case PlatformType::Windows:
|
||||
return "Windows";
|
||||
case PlatformType::Switch:
|
||||
return "Switch";
|
||||
case PlatformType::Linux:
|
||||
return "Linux";
|
||||
case PlatformType::macOS:
|
||||
return "macOS";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -4,6 +4,25 @@
|
|||
|
||||
namespace extra2d {
|
||||
|
||||
E2D_REG_BACKEND(sdl2, SDL2Window, SDL2Input)
|
||||
namespace {
|
||||
static bool s_sdl2BackendRegistered = false;
|
||||
}
|
||||
|
||||
void initSDL2Backend() {
|
||||
if (s_sdl2BackendRegistered) {
|
||||
return;
|
||||
}
|
||||
s_sdl2BackendRegistered = true;
|
||||
|
||||
BackendFactory::reg(
|
||||
"sdl2",
|
||||
[]() -> UniquePtr<IWindow> {
|
||||
return makeUnique<SDL2Window>();
|
||||
},
|
||||
[]() -> UniquePtr<IInput> {
|
||||
return makeUnique<SDL2Input>();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "sdl2_window.h"
|
||||
#include "sdl2_input.h"
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -73,6 +74,16 @@ bool SDL2Window::create(const WindowConfigData& cfg) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
E2D_LOG_ERROR("Failed to initialize GLAD");
|
||||
SDL_GL_DeleteContext(glContext_);
|
||||
glContext_ = nullptr;
|
||||
SDL_DestroyWindow(sdlWindow_);
|
||||
sdlWindow_ = nullptr;
|
||||
deinitSDL();
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_GL_SetSwapInterval(cfg.vsync ? 1 : 0);
|
||||
|
||||
SDL_GetWindowSize(sdlWindow_, &width_, &height_);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* @file main.cpp
|
||||
* @brief Extra2D 基础示例程序
|
||||
*
|
||||
* 演示如何使用 Extra2D 引擎创建一个简单的窗口应用程序。
|
||||
*/
|
||||
|
||||
#include <extra2d/extra2d.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace extra2d;
|
||||
|
||||
/**
|
||||
* @brief 主函数
|
||||
*
|
||||
* 初始化应用程序,创建场景,运行主循环。
|
||||
*/
|
||||
int main(int argc, char* argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
std::cout << "Extra2D Demo - Starting..." << std::endl;
|
||||
|
||||
AppConfig config = AppConfig::createDefault();
|
||||
config.appName = "Extra2D Demo";
|
||||
config.appVersion = "1.0.0";
|
||||
config.window.title = "Extra2D Demo";
|
||||
config.window.width = 800;
|
||||
config.window.height = 600;
|
||||
config.window.mode = WindowMode::Windowed;
|
||||
config.window.resizable = true;
|
||||
config.window.vsync = true;
|
||||
config.render.targetFPS = 60;
|
||||
|
||||
Application& app = Application::get();
|
||||
|
||||
if (!app.init(config)) {
|
||||
std::cerr << "Failed to initialize application!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Application initialized successfully!" << std::endl;
|
||||
std::cout << "Window: " << app.window().width() << "x" << app.window().height() << std::endl;
|
||||
std::cout << "Running main loop. Press ESC or close window to exit." << std::endl;
|
||||
|
||||
auto scene = Scene::create();
|
||||
scene->setBackgroundColor(Colors::SkyBlue);
|
||||
scene->setViewportSize(static_cast<float>(config.window.width),
|
||||
static_cast<float>(config.window.height));
|
||||
app.enterScene(scene);
|
||||
|
||||
app.run();
|
||||
|
||||
std::cout << "Shutting down..." << std::endl;
|
||||
app.shutdown();
|
||||
|
||||
std::cout << "Goodbye!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
20
xmake.lua
20
xmake.lua
|
|
@ -95,3 +95,23 @@ includes("xmake/engine.lua")
|
|||
-- 定义引擎库
|
||||
define_extra2d_engine()
|
||||
|
||||
-- ==============================================
|
||||
-- 示例程序
|
||||
-- ==============================================
|
||||
|
||||
-- 基础示例
|
||||
target("demo_basic")
|
||||
set_kind("binary")
|
||||
set_default(false)
|
||||
|
||||
add_deps("extra2d")
|
||||
add_files("examples/basic/main.cpp")
|
||||
|
||||
-- 平台配置
|
||||
local target_plat = get_config("plat") or os.host()
|
||||
if target_plat == "mingw" then
|
||||
add_packages("glm", "nlohmann_json", "libsdl2")
|
||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
||||
end
|
||||
target_end()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue