diff --git a/Extra2D/include/extra2d/graphics/backends/backend_factory.h b/Extra2D/include/extra2d/graphics/backends/backend_factory.h index 2b1a2e5..2b52214 100644 --- a/Extra2D/include/extra2d/graphics/backends/backend_factory.h +++ b/Extra2D/include/extra2d/graphics/backends/backend_factory.h @@ -1,79 +1,124 @@ #pragma once +#include #include -#include + +#include +#include +#include +#include namespace extra2d { +namespace graphics { /** - * @brief 渲染后端类型枚举 - */ -enum class BackendType { - OpenGL, // OpenGL 4.x - Vulkan, // Vulkan 1.x - Metal, // Metal (macOS/iOS) - D3D11, // Direct3D 11 - D3D12, // Direct3D 12 - OpenGLES, // OpenGL ES (移动平台) - Count -}; - -/** - * @brief 后端工厂类,用于创建渲染后端实例 + * @brief 图形后端工厂 + * 用于注册和创建图形渲染后端 */ class BackendFactory { public: - /** - * @brief 获取后端工厂单例 - * @return 后端工厂实例引用 - */ - static BackendFactory& getInstance(); + using BackendFn = std::function()>; - /** - * @brief 创建渲染后端 - * @param type 后端类型 - * @return 渲染后端实例 - */ - UniquePtr createBackend(BackendType type); + /** + * @brief 注册图形后端 + * @param name 后端名称 + * @param backend 后端创建函数 + * @param windowBackends 支持的窗口后端名称列表 + */ + static void reg(const std::string &name, BackendFn backend, + const std::vector &windowBackends = {}); - /** - * @brief 创建默认渲染后端 - * @return 默认渲染后端实例 - */ - UniquePtr createDefaultBackend(); + /** + * @brief 创建渲染后端实例 + * @param name 后端名称 + * @return 渲染后端实例,如果后端不存在返回 nullptr + */ + static UniquePtr createBackend(const std::string &name); - /** - * @brief 检查后端是否可用 - * @param type 后端类型 - * @return 可用返回true,否则返回false - */ - bool isBackendAvailable(BackendType type) const; + /** + * @brief 创建默认渲染后端 + * @return 默认渲染后端实例 + */ + static UniquePtr createDefaultBackend(); - /** - * @brief 获取当前平台推荐的后端类型 - * @return 推荐的后端类型 - */ - BackendType getRecommendedBackend() const; + /** + * @brief 创建与指定窗口后端兼容的渲染后端 + * @param windowBackend 窗口后端名称 + * @return 兼容的渲染后端实例 + */ + static UniquePtr + createBackendForWindow(const std::string &windowBackend); - /** - * @brief 获取后端类型名称 - * @param type 后端类型 - * @return 后端类型名称字符串 - */ - const char* getBackendName(BackendType type) const; + /** + * @brief 获取所有已注册的后端名称 + */ + static std::vector backends(); - /** - * @brief 从名称解析后端类型 - * @param name 后端类型名称 - * @return 后端类型,如果未知则返回OpenGL - */ - BackendType parseBackendType(const char* name) const; + /** + * @brief 检查后端是否存在 + */ + static bool has(const std::string &name); + + /** + * @brief 获取推荐的后端名称 + * @return 推荐的后端名称 + */ + static std::string getRecommendedBackend(); + + /** + * @brief 获取与指定窗口后端兼容的推荐图形后端 + * @param windowBackend 窗口后端名称 + * @return 推荐的图形后端名称 + */ + static std::string + getRecommendedBackendForWindow(const std::string &windowBackend); + + /** + * @brief 检查图形后端是否支持指定窗口后端 + * @param graphicsBackend 图形后端名称 + * @param windowBackend 窗口后端名称 + * @return 支持返回 true + */ + static bool isCompatible(const std::string &graphicsBackend, + const std::string &windowBackend); + + /** + * @brief 获取图形后端支持的窗口后端列表 + * @param graphicsBackend 图形后端名称 + * @return 支持的窗口后端列表 + */ + static std::vector + getSupportedWindowBackends(const std::string &graphicsBackend); private: - BackendFactory() = default; - ~BackendFactory() = default; - BackendFactory(const BackendFactory&) = delete; - BackendFactory& operator=(const BackendFactory&) = delete; + struct BackendEntry { + BackendFn createFn; + std::vector windowBackends; + }; + + static std::unordered_map ®istry(); }; +/** + * @brief 图形后端注册宏 + * 在全局作用域使用此宏注册图形后端 + * + * @example + * E2D_REG_GRAPHICS_BACKEND(opengl, GLRenderer, {"sdl2", "glfw"}) + */ +#define E2D_REG_GRAPHICS_BACKEND(name, RendererClass, windowBackends) \ + namespace { \ + __attribute__((used)) static struct E2D_GRAPHICS_BACKEND_REG_##name { \ + E2D_GRAPHICS_BACKEND_REG_##name() { \ + ::extra2d::graphics::BackendFactory::reg( \ + #name, \ + []() -> ::extra2d::UniquePtr<::extra2d::RenderBackend> { \ + return ::extra2d::makeUnique(); \ + }, \ + windowBackends); \ + } \ + } e2d_graphics_backend_reg_##name; \ + } + +} // namespace graphics } // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/core/render_backend.h b/Extra2D/include/extra2d/graphics/core/render_backend.h index 98369e5..b12bcb4 100644 --- a/Extra2D/include/extra2d/graphics/core/render_backend.h +++ b/Extra2D/include/extra2d/graphics/core/render_backend.h @@ -14,17 +14,6 @@ class Texture; class FontAtlas; class Shader; -// ============================================================================ -// 渲染后端类型 -// ============================================================================ -enum class BackendType { - OpenGL, - // Vulkan, - // Metal, - // D3D11, - // D3D12 -}; - // BlendMode 定义在 pipeline.h 中 // ============================================================================ @@ -131,11 +120,6 @@ public: }; virtual Stats getStats() const = 0; virtual void resetStats() = 0; - - // ------------------------------------------------------------------------ - // 工厂方法 - // ------------------------------------------------------------------------ - static UniquePtr create(BackendType type); }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/core/render_module.h b/Extra2D/include/extra2d/graphics/core/render_module.h index cee6bdd..9a282b9 100644 --- a/Extra2D/include/extra2d/graphics/core/render_module.h +++ b/Extra2D/include/extra2d/graphics/core/render_module.h @@ -12,14 +12,14 @@ namespace extra2d { * @brief 渲染模块配置结构 */ struct RenderCfg { - BackendType backend; + std::string backend; int targetFPS; bool vsync; int multisamples; int priority; RenderCfg() - : backend(BackendType::OpenGL) + : backend("") , targetFPS(60) , vsync(true) , multisamples(0) @@ -29,7 +29,7 @@ struct RenderCfg { /** * @brief 渲染模块 - * 管理渲染后端 + * 管理渲染后端,自动根据窗口后端选择兼容的渲染器 */ class RenderModule : public Module { public: diff --git a/Extra2D/include/extra2d/platform/backend_factory.h b/Extra2D/include/extra2d/platform/backend_factory.h index b6b1b89..eafe4aa 100644 --- a/Extra2D/include/extra2d/platform/backend_factory.h +++ b/Extra2D/include/extra2d/platform/backend_factory.h @@ -1,14 +1,15 @@ #pragma once #include -#include #include +#include #include +#include #include #include -#include namespace extra2d { +namespace platform { /** * @brief 平台后端工厂 @@ -16,73 +17,72 @@ namespace extra2d { */ class BackendFactory { public: - using WindowFn = std::function()>; - using InputFn = std::function()>; + using WindowFn = std::function()>; + using InputFn = std::function()>; - /** - * @brief 注册平台后端 - * @param name 后端名称 - * @param win 窗口创建函数 - * @param in 输入创建函数 - */ - static void reg(const std::string& name, WindowFn win, InputFn in); + /** + * @brief 注册平台后端 + * @param name 后端名称 + * @param win 窗口创建函数 + * @param in 输入创建函数 + */ + static void reg(const std::string &name, WindowFn win, InputFn in); - /** - * @brief 创建窗口实例 - * @param name 后端名称 - * @return 窗口实例,如果后端不存在返回 nullptr - */ - static UniquePtr createWindow(const std::string& name); + /** + * @brief 创建窗口实例 + * @param name 后端名称 + * @return 窗口实例,如果后端不存在返回 nullptr + */ + static UniquePtr createWindow(const std::string &name); - /** - * @brief 创建输入实例 - * @param name 后端名称 - * @return 输入实例,如果后端不存在返回 nullptr - */ - static UniquePtr createInput(const std::string& name); + /** + * @brief 创建输入实例 + * @param name 后端名称 + * @return 输入实例,如果后端不存在返回 nullptr + */ + static UniquePtr createInput(const std::string &name); - /** - * @brief 获取所有已注册的后端名称 - */ - static std::vector backends(); + /** + * @brief 获取所有已注册的后端名称 + */ + static std::vector backends(); - /** - * @brief 检查后端是否存在 - */ - static bool has(const std::string& name); + /** + * @brief 检查后端是否存在 + */ + static bool has(const std::string &name); private: - struct BackendEntry { - WindowFn windowFn; - InputFn inputFn; - }; + struct BackendEntry { + WindowFn windowFn; + InputFn inputFn; + }; - static std::unordered_map& registry(); + static std::unordered_map ®istry(); }; /** * @brief 平台后端注册宏 * 在全局作用域使用此宏注册平台后端 - * + * * @example * E2D_REG_BACKEND(sdl2, SDL2Window, SDL2Input) */ -#define E2D_REG_BACKEND(name, WinClass, InClass) \ - namespace { \ - __attribute__((used)) \ - static struct E2D_BACKEND_REG_##name { \ - E2D_BACKEND_REG_##name() { \ - ::extra2d::BackendFactory::reg( \ - #name, \ - []() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \ - return ::extra2d::makeUnique(); \ - }, \ - []() -> ::extra2d::UniquePtr<::extra2d::IInput> { \ - return ::extra2d::makeUnique(); \ - } \ - ); \ - } \ - } e2d_backend_reg_##name; \ - } +#define E2D_REG_BACKEND(name, WinClass, InClass) \ + namespace { \ + __attribute__((used)) static struct E2D_BACKEND_REG_##name { \ + E2D_BACKEND_REG_##name() { \ + ::extra2d::platform::BackendFactory::reg( \ + #name, \ + []() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \ + return ::extra2d::makeUnique(); \ + }, \ + []() -> ::extra2d::UniquePtr<::extra2d::IInput> { \ + return ::extra2d::makeUnique(); \ + }); \ + } \ + } e2d_backend_reg_##name; \ + } +} // namespace platform } // namespace extra2d diff --git a/Extra2D/include/extra2d/platform/iwindow.h b/Extra2D/include/extra2d/platform/iwindow.h index b5fbff8..14751db 100644 --- a/Extra2D/include/extra2d/platform/iwindow.h +++ b/Extra2D/include/extra2d/platform/iwindow.h @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -33,10 +32,13 @@ public: /** * @brief 创建窗口 - * @param cfg 窗口配置 + * @param title 窗口标题 + * @param width 窗口宽度 + * @param height 窗口高度 + * @param vsync 是否启用垂直同步 * @return 创建是否成功 */ - virtual bool create(const WindowConfigData& cfg) = 0; + virtual bool create(const std::string& title, int width, int height, bool vsync = true) = 0; /** * @brief 销毁窗口 diff --git a/Extra2D/include/extra2d/platform/window_config.h b/Extra2D/include/extra2d/platform/window_config.h deleted file mode 100644 index ab2a4cb..0000000 --- a/Extra2D/include/extra2d/platform/window_config.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include - -namespace extra2d { - -/** - * @file window_config.h - * @brief 窗口模块配置 - * - * 定义窗口相关的配置数据结构,由 WindowModule 管理。 - */ - -/** - * @brief 窗口模式枚举 - */ -enum class WindowMode { - Windowed, - Fullscreen, - Borderless -}; - -/** - * @brief 窗口配置数据结构 - */ -struct WindowConfigData { - std::string title = "Extra2D Application"; - int width = 1280; - int height = 720; - int minWidth = 320; - int minHeight = 240; - int maxWidth = 0; - int maxHeight = 0; - WindowMode mode = WindowMode::Windowed; - bool resizable = true; - bool borderless = false; - bool alwaysOnTop = false; - bool centered = true; - int posX = -1; - int posY = -1; - bool hideOnClose = false; - bool minimizeOnClose = true; - float opacity = 1.0f; - bool transparentFramebuffer = false; - bool highDPI = true; - float contentScale = 1.0f; - bool vsync = true; - int multisamples = 0; - bool visible = true; - bool decorated = true; - - /** - * @brief 检查窗口尺寸是否有效 - * @return 如果宽高都大于0返回 true - */ - bool isSizeValid() const { return width > 0 && height > 0; } - - /** - * @brief 检查是否设置了窗口位置 - * @return 如果设置了有效位置返回 true - */ - bool hasPosition() const { return posX >= 0 && posY >= 0; } - - /** - * @brief 获取窗口宽高比 - * @return 宽高比值 - */ - float aspectRatio() const { return static_cast(width) / static_cast(height); } - - /** - * @brief 检查是否为全屏模式 - * @return 如果是全屏模式返回 true - */ - bool isFullscreen() const { return mode == WindowMode::Fullscreen; } - - /** - * @brief 检查是否为无边框模式 - * @return 如果是无边框模式返回 true - */ - bool isBorderless() const { return mode == WindowMode::Borderless || borderless; } -}; - -} diff --git a/Extra2D/include/extra2d/platform/window_module.h b/Extra2D/include/extra2d/platform/window_module.h index bb952bd..6aa058c 100644 --- a/Extra2D/include/extra2d/platform/window_module.h +++ b/Extra2D/include/extra2d/platform/window_module.h @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -15,14 +14,13 @@ struct WindowCfg { std::string title; int w; int h; - WindowMode mode; bool vsync; int priority; std::string backend; WindowCfg() - : title("Extra2D"), w(1280), h(720), mode(WindowMode::Windowed), - vsync(true), priority(0), backend("sdl2") {} + : title("Extra2D"), w(1280), h(720), vsync(true), priority(0), + backend("sdl2") {} }; /** @@ -54,11 +52,16 @@ public: */ IWindow *win() const { return win_.get(); } + /** + * @brief 获取窗口后端名称 + * @return 窗口后端名称 + */ + const std::string &getWindowBackend() const { return cfg_.backend; } + private: WindowCfg cfg_; UniquePtr win_; bool initialized_ = false; - bool sdlInited_ = false; }; } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/backend_factory.cpp b/Extra2D/src/graphics/backends/backend_factory.cpp index 27b66c5..5f29487 100644 --- a/Extra2D/src/graphics/backends/backend_factory.cpp +++ b/Extra2D/src/graphics/backends/backend_factory.cpp @@ -1,127 +1,136 @@ #include - -// 条件编译包含对应后端实现 -#ifdef E2D_BACKEND_OPENGL -#include -#endif - -#ifdef E2D_BACKEND_VULKAN -#include -#endif - #include -#include namespace extra2d { +namespace graphics { -BackendFactory& BackendFactory::getInstance() { - static BackendFactory instance; - return instance; +std::unordered_map& BackendFactory::registry() { + static std::unordered_map reg; + return reg; } -UniquePtr BackendFactory::createBackend(BackendType type) { - switch (type) { -#ifdef E2D_BACKEND_OPENGL - case BackendType::OpenGL: - E2D_LOG_INFO("Creating OpenGL render backend"); - return makeUnique(); -#endif +void BackendFactory::reg(const std::string& name, BackendFn backend, + const std::vector& windowBackends) { + registry()[name] = {backend, windowBackends}; + E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", + name, windowBackends.size()); +} -#ifdef E2D_BACKEND_VULKAN - case BackendType::Vulkan: - E2D_LOG_INFO("Creating Vulkan render backend"); - return makeUnique(); -#endif - - default: - E2D_LOG_ERROR("Unsupported render backend type: {}", static_cast(type)); - return nullptr; +UniquePtr BackendFactory::createBackend(const std::string& name) { + auto& reg = registry(); + auto it = reg.find(name); + if (it != reg.end() && it->second.createFn) { + E2D_LOG_INFO("Creating graphics backend: {}", name); + return it->second.createFn(); } + E2D_LOG_ERROR("Graphics backend '{}' not found", name); + return nullptr; } UniquePtr BackendFactory::createDefaultBackend() { - BackendType recommended = getRecommendedBackend(); + std::string recommended = getRecommendedBackend(); + if (recommended.empty()) { + E2D_LOG_ERROR("No graphics backend available"); + return nullptr; + } return createBackend(recommended); } -bool BackendFactory::isBackendAvailable(BackendType type) const { - switch (type) { -#ifdef E2D_BACKEND_OPENGL - case BackendType::OpenGL: +UniquePtr BackendFactory::createBackendForWindow(const std::string& windowBackend) { + std::string recommended = getRecommendedBackendForWindow(windowBackend); + if (recommended.empty()) { + E2D_LOG_ERROR("No compatible graphics backend for window backend: {}", windowBackend); + return nullptr; + } + return createBackend(recommended); +} + +std::vector BackendFactory::backends() { + std::vector result; + for (const auto& pair : registry()) { + result.push_back(pair.first); + } + return result; +} + +bool BackendFactory::has(const std::string& name) { + return registry().find(name) != registry().end(); +} + +std::string BackendFactory::getRecommendedBackend() { + auto& reg = registry(); + + static const std::vector priority = { + "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles" + }; + + for (const auto& name : priority) { + if (reg.find(name) != reg.end()) { + return name; + } + } + + if (!reg.empty()) { + return reg.begin()->first; + } + + E2D_LOG_WARN("No graphics backend registered"); + return ""; +} + +std::string BackendFactory::getRecommendedBackendForWindow(const std::string& windowBackend) { + auto& reg = registry(); + + static const std::vector priority = { + "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles" + }; + + for (const auto& name : priority) { + auto it = reg.find(name); + if (it != reg.end() && isCompatible(name, windowBackend)) { + return name; + } + } + + for (const auto& pair : reg) { + if (isCompatible(pair.first, windowBackend)) { + return pair.first; + } + } + + E2D_LOG_WARN("No compatible graphics backend for window backend: {}", windowBackend); + return ""; +} + +bool BackendFactory::isCompatible(const std::string& graphicsBackend, const std::string& windowBackend) { + auto& reg = registry(); + auto it = reg.find(graphicsBackend); + if (it == reg.end()) { + return false; + } + + const auto& windowBackends = it->second.windowBackends; + if (windowBackends.empty()) { + return true; + } + + for (const auto& wb : windowBackends) { + if (wb == windowBackend) { return true; -#endif - -#ifdef E2D_BACKEND_VULKAN - case BackendType::Vulkan: - return true; -#endif - - default: - return false; + } } + + return false; } -BackendType BackendFactory::getRecommendedBackend() const { - // 平台特定的默认后端选择 - // 优先级:Vulkan > OpenGL - -#ifdef E2D_BACKEND_VULKAN - return BackendType::Vulkan; -#endif - -#ifdef E2D_BACKEND_OPENGL - return BackendType::OpenGL; -#endif - - // 如果没有可用的后端,返回OpenGL作为默认值 - return BackendType::OpenGL; -} - -const char* BackendFactory::getBackendName(BackendType type) const { - switch (type) { - case BackendType::OpenGL: - return "OpenGL"; - case BackendType::Vulkan: - return "Vulkan"; - case BackendType::Metal: - return "Metal"; - case BackendType::D3D11: - return "D3D11"; - case BackendType::D3D12: - return "D3D12"; - case BackendType::OpenGLES: - return "OpenGL ES"; - default: - return "Unknown"; - } -} - -BackendType BackendFactory::parseBackendType(const char* name) const { - if (!name) { - return BackendType::OpenGL; - } - - if (std::strcmp(name, "opengl") == 0 || std::strcmp(name, "OpenGL") == 0) { - return BackendType::OpenGL; - } - if (std::strcmp(name, "vulkan") == 0 || std::strcmp(name, "Vulkan") == 0) { - return BackendType::Vulkan; - } - if (std::strcmp(name, "metal") == 0 || std::strcmp(name, "Metal") == 0) { - return BackendType::Metal; - } - if (std::strcmp(name, "d3d11") == 0 || std::strcmp(name, "D3D11") == 0) { - return BackendType::D3D11; - } - if (std::strcmp(name, "d3d12") == 0 || std::strcmp(name, "D3D12") == 0) { - return BackendType::D3D12; - } - if (std::strcmp(name, "opengles") == 0 || std::strcmp(name, "OpenGLES") == 0) { - return BackendType::OpenGLES; - } - - E2D_LOG_WARN("Unknown backend type '{}', defaulting to OpenGL", name); - return BackendType::OpenGL; +std::vector BackendFactory::getSupportedWindowBackends(const std::string& graphicsBackend) { + auto& reg = registry(); + auto it = reg.find(graphicsBackend); + if (it != reg.end()) { + return it->second.windowBackends; + } + return {}; } +} // namespace graphics } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/opengl/gl_backend.cpp b/Extra2D/src/graphics/backends/opengl/gl_backend.cpp new file mode 100644 index 0000000..d34b6e5 --- /dev/null +++ b/Extra2D/src/graphics/backends/opengl/gl_backend.cpp @@ -0,0 +1,39 @@ +#include +#include + +namespace extra2d { +namespace graphics { + +namespace { + static bool s_openglBackendRegistered = false; +} + +/** + * @brief 初始化 OpenGL 后端注册 + */ +void initOpenGLBackend() { + if (s_openglBackendRegistered) { + return; + } + s_openglBackendRegistered = true; + + BackendFactory::reg( + "opengl", + []() -> UniquePtr { + return makeUnique(); + }, + {"sdl2", "glfw"} + ); +} + +namespace { + struct OpenGLBackendAutoReg { + OpenGLBackendAutoReg() { + initOpenGLBackend(); + } + }; + static OpenGLBackendAutoReg s_openglAutoReg; +} + +} // namespace graphics +} // namespace extra2d diff --git a/Extra2D/src/graphics/backends/vulkan/vk_backend.cpp b/Extra2D/src/graphics/backends/vulkan/vk_backend.cpp new file mode 100644 index 0000000..095e234 --- /dev/null +++ b/Extra2D/src/graphics/backends/vulkan/vk_backend.cpp @@ -0,0 +1,39 @@ +#include +#include + +namespace extra2d { +namespace graphics { + +namespace { + static bool s_vulkanBackendRegistered = false; +} + +/** + * @brief 初始化 Vulkan 后端注册 + */ +void initVulkanBackend() { + if (s_vulkanBackendRegistered) { + return; + } + s_vulkanBackendRegistered = true; + + BackendFactory::reg( + "vulkan", + []() -> UniquePtr { + return makeUnique(); + }, + {"sdl2", "glfw"} + ); +} + +namespace { + struct VulkanBackendAutoReg { + VulkanBackendAutoReg() { + initVulkanBackend(); + } + }; + static VulkanBackendAutoReg s_vulkanAutoReg; +} + +} // namespace graphics +} // namespace extra2d diff --git a/Extra2D/src/graphics/core/render_backend.cpp b/Extra2D/src/graphics/core/render_backend.cpp deleted file mode 100644 index 82e05d4..0000000 --- a/Extra2D/src/graphics/core/render_backend.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -namespace extra2d { - -/** - * @brief 创建渲染后端实例 - * - * 根据指定的后端类型创建对应的渲染后端实例, - * 目前支持OpenGL后端 - * - * @param type 渲染后端类型(如OpenGL) - * @return 成功返回渲染后端的唯一指针,不支持的类型返回nullptr - */ -UniquePtr RenderBackend::create(BackendType type) { - switch (type) { - case BackendType::OpenGL: - return makeUnique(); - default: - return nullptr; - } -} - -} // namespace extra2d diff --git a/Extra2D/src/graphics/core/render_module.cpp b/Extra2D/src/graphics/core/render_module.cpp index 5043fad..3b43d68 100644 --- a/Extra2D/src/graphics/core/render_module.cpp +++ b/Extra2D/src/graphics/core/render_module.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -11,6 +11,16 @@ namespace extra2d { +// 前向声明后端初始化函数 +namespace graphics { +#ifdef E2D_BACKEND_OPENGL +void initOpenGLBackend(); +#endif +#ifdef E2D_BACKEND_VULKAN +void initVulkanBackend(); +#endif +} + RenderModule::RenderModule(std::function configFn) { configFn(cfg_); } @@ -33,13 +43,20 @@ static std::string getExecutableDir() { bool RenderModule::init() { if (initialized_) return true; - // 获取WindowModule依赖 auto* winMod = Registry::instance().get(); if (!winMod || !winMod->win()) { + E2D_LOG_ERROR("WindowModule not available"); return false; } - // 初始化ShaderManager + // 初始化图形后端(注册到工厂) +#ifdef E2D_BACKEND_OPENGL + graphics::initOpenGLBackend(); +#endif +#ifdef E2D_BACKEND_VULKAN + graphics::initVulkanBackend(); +#endif + if (!ShaderManager::getInstance().isInitialized()) { auto factory = makeShared(); std::string shaderDir = getExecutableDir() + "shaders/"; @@ -49,18 +66,31 @@ bool RenderModule::init() { } } - // 创建渲染后端 - renderer_ = RenderBackend::create(cfg_.backend); + std::string windowBackend = winMod->getWindowBackend(); + + if (cfg_.backend.empty()) { + E2D_LOG_INFO("No graphics backend specified, auto-selecting for window backend: {}", windowBackend); + renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend); + } else { + if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) { + E2D_LOG_WARN("Graphics backend '{}' is not compatible with window backend '{}'", + cfg_.backend, windowBackend); + } + renderer_ = graphics::BackendFactory::createBackend(cfg_.backend); + } + if (!renderer_) { + E2D_LOG_ERROR("Failed to create render backend"); return false; } - // 初始化渲染器 if (!renderer_->init(winMod->win())) { + E2D_LOG_ERROR("Failed to initialize render backend"); renderer_.reset(); return false; } + E2D_LOG_INFO("Render module initialized successfully"); initialized_ = true; return true; } diff --git a/Extra2D/src/platform/backend_factory.cpp b/Extra2D/src/platform/backend_factory.cpp index 9759d9d..ece530c 100644 --- a/Extra2D/src/platform/backend_factory.cpp +++ b/Extra2D/src/platform/backend_factory.cpp @@ -1,6 +1,7 @@ #include namespace extra2d { +namespace platform { std::unordered_map& BackendFactory::registry() { static std::unordered_map reg; @@ -41,4 +42,5 @@ bool BackendFactory::has(const std::string& name) { return registry().find(name) != registry().end(); } +} // namespace platform } // namespace extra2d diff --git a/Extra2D/src/platform/backends/glfw/glfw_backend.cpp b/Extra2D/src/platform/backends/glfw/glfw_backend.cpp index 9468940..7e688bc 100644 --- a/Extra2D/src/platform/backends/glfw/glfw_backend.cpp +++ b/Extra2D/src/platform/backends/glfw/glfw_backend.cpp @@ -3,6 +3,7 @@ #include namespace extra2d { +namespace platform { namespace { static bool s_glfwBackendRegistered = false; @@ -25,4 +26,5 @@ void initGLFWBackend() { ); } +} // namespace platform } // namespace extra2d diff --git a/Extra2D/src/platform/backends/glfw/glfw_window.cpp b/Extra2D/src/platform/backends/glfw/glfw_window.cpp index de95e3e..32057e8 100644 --- a/Extra2D/src/platform/backends/glfw/glfw_window.cpp +++ b/Extra2D/src/platform/backends/glfw/glfw_window.cpp @@ -11,12 +11,11 @@ GLFWWindow::~GLFWWindow() { destroy(); } -bool GLFWWindow::create(const WindowConfigData& cfg) { +bool GLFWWindow::create(const std::string& title, int width, int height, bool vsync) { if (!initGLFW()) { return false; } - // 设置 OpenGL ES 3.2 上下文 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); @@ -26,44 +25,21 @@ bool GLFWWindow::create(const WindowConfigData& cfg) { glfwWindowHint(GLFW_STENCIL_BITS, 8); #ifdef __SWITCH__ - // Switch 平台强制全屏 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); fullscreen_ = true; #else - // 桌面平台配置 - if (cfg.resizable) { - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - } else { - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - } - - if (!cfg.decorated) { - glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); - } - - if (cfg.isFullscreen()) { - glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); - fullscreen_ = true; - } + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); #endif - if (cfg.multisamples > 0) { - glfwWindowHint(GLFW_SAMPLES, cfg.multisamples); - } - - // 创建窗口 GLFWmonitor* monitor = nullptr; #ifdef __SWITCH__ monitor = glfwGetPrimaryMonitor(); #endif - if (fullscreen_ && !monitor) { - monitor = glfwGetPrimaryMonitor(); - } glfwWindow_ = glfwCreateWindow( - cfg.width, cfg.height, - cfg.title.c_str(), + width, height, + title.c_str(), monitor, nullptr ); @@ -74,7 +50,6 @@ bool GLFWWindow::create(const WindowConfigData& cfg) { return false; } - // 窗口居中(非全屏模式下) #ifndef __SWITCH__ if (!fullscreen_ && !monitor) { GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor(); @@ -83,8 +58,8 @@ bool GLFWWindow::create(const WindowConfigData& cfg) { if (mode) { int screenWidth = mode->width; int screenHeight = mode->height; - int windowX = (screenWidth - cfg.width) / 2; - int windowY = (screenHeight - cfg.height) / 2; + int windowX = (screenWidth - width) / 2; + int windowY = (screenHeight - height) / 2; glfwSetWindowPos(glfwWindow_, windowX, windowY); } } @@ -93,7 +68,6 @@ bool GLFWWindow::create(const WindowConfigData& cfg) { glfwMakeContextCurrent(glfwWindow_); - // 初始化 GLAD if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) { E2D_LOG_ERROR("Failed to initialize GLAD GLES2"); glfwDestroyWindow(glfwWindow_); @@ -102,15 +76,12 @@ bool GLFWWindow::create(const WindowConfigData& cfg) { return false; } - // 设置垂直同步 - glfwSwapInterval(cfg.vsync ? 1 : 0); - vsync_ = cfg.vsync; + glfwSwapInterval(vsync ? 1 : 0); + vsync_ = vsync; - // 获取实际窗口大小 glfwGetWindowSize(glfwWindow_, &width_, &height_); updateContentScale(); - // 设置回调函数 glfwSetWindowUserPointer(glfwWindow_, this); glfwSetFramebufferSizeCallback(glfwWindow_, framebufferSizeCallback); glfwSetWindowCloseCallback(glfwWindow_, windowCloseCallback); @@ -122,7 +93,6 @@ bool GLFWWindow::create(const WindowConfigData& cfg) { glfwSetKeyCallback(glfwWindow_, keyCallback); glfwSetJoystickCallback(joystickCallback); - // 创建输入系统 input_ = makeUnique(); input_->setWindow(glfwWindow_); input_->init(); diff --git a/Extra2D/src/platform/backends/glfw/glfw_window.h b/Extra2D/src/platform/backends/glfw/glfw_window.h index 7166a45..66da235 100644 --- a/Extra2D/src/platform/backends/glfw/glfw_window.h +++ b/Extra2D/src/platform/backends/glfw/glfw_window.h @@ -15,7 +15,7 @@ public: GLFWWindow(); ~GLFWWindow() override; - bool create(const WindowConfigData& cfg) override; + bool create(const std::string& title, int width, int height, bool vsync = true) override; void destroy() override; void poll() override; diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp b/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp index 483aecf..71b6ba2 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp +++ b/Extra2D/src/platform/backends/sdl2/sdl2_backend.cpp @@ -3,6 +3,7 @@ #include namespace extra2d { +namespace platform { namespace { static bool s_sdl2BackendRegistered = false; @@ -25,4 +26,5 @@ void initSDL2Backend() { ); } +} // namespace platform } // namespace extra2d diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp b/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp index 123c007..c4239b4 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp +++ b/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp @@ -15,27 +15,15 @@ SDL2Window::~SDL2Window() { destroy(); } -bool SDL2Window::create(const WindowConfigData& cfg) { +bool SDL2Window::create(const std::string& title, int width, int height, bool vsync) { if (!initSDL()) { return false; } - Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; + Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; #ifdef __SWITCH__ flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; -#else - if (cfg.isFullscreen()) { - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - } else if (cfg.isBorderless()) { - flags |= SDL_WINDOW_BORDERLESS; - } - if (cfg.resizable) { - flags |= SDL_WINDOW_RESIZABLE; - } - if (!cfg.decorated) { - flags |= SDL_WINDOW_BORDERLESS; - } #endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); @@ -46,22 +34,10 @@ bool SDL2Window::create(const WindowConfigData& cfg) { SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - if (cfg.multisamples > 0) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, cfg.multisamples); - } - - int x = SDL_WINDOWPOS_CENTERED; - int y = SDL_WINDOWPOS_CENTERED; - if (!cfg.centered) { - x = SDL_WINDOWPOS_UNDEFINED; - y = SDL_WINDOWPOS_UNDEFINED; - } - sdlWindow_ = SDL_CreateWindow( - cfg.title.c_str(), - x, y, - cfg.width, cfg.height, + title.c_str(), + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + width, height, flags ); @@ -90,11 +66,11 @@ bool SDL2Window::create(const WindowConfigData& cfg) { return false; } - SDL_GL_SetSwapInterval(cfg.vsync ? 1 : 0); + SDL_GL_SetSwapInterval(vsync ? 1 : 0); SDL_GetWindowSize(sdlWindow_, &width_, &height_); fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; - vsync_ = cfg.vsync; + vsync_ = vsync; #ifndef __SWITCH__ initCursors(); diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_window.h b/Extra2D/src/platform/backends/sdl2/sdl2_window.h index 6bbd18c..fa628e2 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_window.h +++ b/Extra2D/src/platform/backends/sdl2/sdl2_window.h @@ -15,7 +15,7 @@ public: SDL2Window(); ~SDL2Window() override; - bool create(const WindowConfigData& cfg) override; + bool create(const std::string& title, int width, int height, bool vsync = true) override; void destroy() override; void poll() override; diff --git a/Extra2D/src/platform/window_module.cpp b/Extra2D/src/platform/window_module.cpp index b9645c7..04a274d 100644 --- a/Extra2D/src/platform/window_module.cpp +++ b/Extra2D/src/platform/window_module.cpp @@ -10,11 +10,13 @@ namespace extra2d { // 前向声明后端初始化函数 +namespace platform { #if defined(E2D_BACKEND_SDL2) void initSDL2Backend(); #elif defined(E2D_BACKEND_GLFW) void initGLFWBackend(); #endif +} WindowModule::WindowModule(std::function configFn) { configFn(cfg_); @@ -29,39 +31,27 @@ WindowModule::~WindowModule() { bool WindowModule::init() { if (initialized_) return true; -#ifdef __SWITCH__ - cfg_.mode = WindowMode::Fullscreen; -#endif - // 初始化后端(注册到工厂) #if defined(E2D_BACKEND_SDL2) - initSDL2Backend(); + platform::initSDL2Backend(); #elif defined(E2D_BACKEND_GLFW) - initGLFWBackend(); + platform::initGLFWBackend(); #else #error "No window backend defined" #endif E2D_LOG_INFO("Window backend initialized"); - // 创建窗口配置 - WindowConfigData winCfg; - winCfg.title = cfg_.title; - winCfg.width = cfg_.w; - winCfg.height = cfg_.h; - winCfg.mode = cfg_.mode; - winCfg.vsync = cfg_.vsync; - E2D_LOG_INFO("Creating window with size {}x{}", cfg_.w, cfg_.h); // 创建窗口(使用配置的后端) - win_ = BackendFactory::createWindow(cfg_.backend); + win_ = platform::BackendFactory::createWindow(cfg_.backend); if (!win_) { E2D_LOG_ERROR("Failed to create window backend: {}", cfg_.backend); return false; } - if (!win_->create(winCfg)) { + if (!win_->create(cfg_.title, cfg_.w, cfg_.h, cfg_.vsync)) { E2D_LOG_ERROR("Failed to create window"); shutdown(); return false; diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp index 84b2dd7..02a0983 100644 --- a/examples/basic/main.cpp +++ b/examples/basic/main.cpp @@ -3,95 +3,95 @@ * @brief Extra2D 场景图测试示例 */ -#include #include -#include -#include -#include -#include -#include #include using namespace extra2d; -void createSceneGraph(Scene *scene) { - float width = scene->getWidth(); - float height = scene->getHeight(); +/** + * @brief 基础场景类,演示场景图功能 + */ +class BasicScene : public Scene { +public: + /** + * @brief 场景进入时初始化场景图 + */ + void onEnter() override { + float width = getWidth(); + float height = getHeight(); - auto root = makeShared(); - root->setName("Root"); - root->setPos(width / 2, height / 2); - scene->addChild(root); + auto root = makeShared(); + root->setName("Root"); + root->setPos(width / 2, height / 2); + addChild(root); - auto parent1 = makeShared(); - parent1->setName("Parent1"); - parent1->setPos(-200, 0); - root->addChild(parent1); + auto parent1 = makeShared(); + parent1->setName("Parent1"); + parent1->setPos(-200, 0); + root->addChild(parent1); - auto rect1 = ShapeNode::createFilledRect(Rect(-50, -50, 100, 100), - Color(1.0f, 0.4f, 0.4f, 1.0f)); - rect1->setName("RedRect"); - parent1->addChild(rect1); + auto rect1 = ShapeNode::createFilledRect(Rect(-50, -50, 100, 100), + Color(1.0f, 0.4f, 0.4f, 1.0f)); + rect1->setName("RedRect"); + parent1->addChild(rect1); - auto child1 = makeShared(); - child1->setName("Child1"); - child1->setPos(80, 0); - child1->setRotation(45); - child1->setScale(0.5f); - parent1->addChild(child1); + auto child1 = makeShared(); + child1->setName("Child1"); + child1->setPos(80, 0); + child1->setRotation(45); + child1->setScale(0.5f); + parent1->addChild(child1); - auto smallRect = ShapeNode::createFilledRect(Rect(-30, -30, 60, 60), - Color(1.0f, 0.8f, 0.4f, 1.0f)); - smallRect->setName("OrangeRect"); - child1->addChild(smallRect); + auto smallRect = ShapeNode::createFilledRect(Rect(-30, -30, 60, 60), + Color(1.0f, 0.8f, 0.4f, 1.0f)); + smallRect->setName("OrangeRect"); + child1->addChild(smallRect); - auto parent2 = makeShared(); - parent2->setName("Parent2"); - parent2->setPos(200, 0); - root->addChild(parent2); + auto parent2 = makeShared(); + parent2->setName("Parent2"); + parent2->setPos(200, 0); + root->addChild(parent2); - auto circle1 = ShapeNode::createFilledCircle(Vec2(0, 0), 60, - Color(0.4f, 0.4f, 1.0f, 1.0f)); - circle1->setName("BlueCircle"); - parent2->addChild(circle1); + auto circle1 = ShapeNode::createFilledCircle(Vec2(0, 0), 60, + Color(0.4f, 0.4f, 1.0f, 1.0f)); + circle1->setName("BlueCircle"); + parent2->addChild(circle1); - auto child2 = makeShared(); - child2->setName("Child2"); - child2->setPos(0, 100); - parent2->addChild(child2); + auto child2 = makeShared(); + child2->setName("Child2"); + child2->setPos(0, 100); + parent2->addChild(child2); - auto triangle = ShapeNode::createFilledTriangle( - Vec2(0, -40), Vec2(-35, 30), Vec2(35, 30), Color(0.4f, 1.0f, 0.4f, 1.0f)); - triangle->setName("GreenTriangle"); - child2->addChild(triangle); + auto triangle = ShapeNode::createFilledTriangle( + Vec2(0, -40), Vec2(-35, 30), Vec2(35, 30), + Color(0.4f, 1.0f, 0.4f, 1.0f)); + triangle->setName("GreenTriangle"); + child2->addChild(triangle); - auto line = ShapeNode::createLine(Vec2(-300, -200), Vec2(300, -200), - Color(1.0f, 1.0f, 1.0f, 1.0f), 2.0f); - line->setName("BottomLine"); - root->addChild(line); + auto line = ShapeNode::createLine(Vec2(-300, -200), Vec2(300, -200), + Color(1.0f, 1.0f, 1.0f, 1.0f), 2.0f); + line->setName("BottomLine"); + root->addChild(line); - auto polygon = ShapeNode::createFilledPolygon( - {Vec2(0, -50), Vec2(50, 0), Vec2(30, 50), Vec2(-30, 50), Vec2(-50, 0)}, - Color(1.0f, 0.4f, 1.0f, 1.0f)); - polygon->setName("PurplePolygon"); - polygon->setPos(0, -150); - root->addChild(polygon); + auto polygon = ShapeNode::createFilledPolygon( + {Vec2(0, -50), Vec2(50, 0), Vec2(30, 50), Vec2(-30, 50), Vec2(-50, 0)}, + Color(1.0f, 0.4f, 1.0f, 1.0f)); + polygon->setName("PurplePolygon"); + polygon->setPos(0, -150); + root->addChild(polygon); + } - std::cout << "\n=== Scene Graph Structure ===" << std::endl; - std::cout << "Scene (root)" << std::endl; - std::cout << " └── Root (center)" << std::endl; - std::cout << " ├── Parent1 (left)" << std::endl; - std::cout << " │ ├── RedRect (100x100)" << std::endl; - std::cout << " │ └── Child1 (rotated 45, scaled 0.5)" << std::endl; - std::cout << " │ └── OrangeRect (60x60)" << std::endl; - std::cout << " ├── Parent2 (right)" << std::endl; - std::cout << " │ ├── BlueCircle (radius 60)" << std::endl; - std::cout << " │ └── Child2 (below)" << std::endl; - std::cout << " │ └── GreenTriangle" << std::endl; - std::cout << " ├── BottomLine" << std::endl; - std::cout << " └── PurplePolygon (pentagon)" << std::endl; - std::cout << "=============================\n" << std::endl; -} + /** + * @brief 场景退出时清理资源 + */ + void onExit() override { clearChildren(); } + + /** + * @brief 自定义渲染逻辑 + * @param renderer 渲染后端 + */ + void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); } +}; int main(int argc, char *argv[]) { (void)argc; @@ -101,7 +101,6 @@ int main(int argc, char *argv[]) { Application &app = Application::get(); - // 注册模块(按优先级顺序) app.use([](auto &cfg) { cfg.w = 1280; cfg.h = 720; @@ -109,7 +108,10 @@ int main(int argc, char *argv[]) { cfg.backend = "glfw"; }); - app.use([](auto &cfg) { cfg.priority = 10; }); + app.use([](auto &cfg) { + cfg.priority = 10; + cfg.backend = "opengl"; + }); app.use([](auto &cfg) { cfg.priority = 20; }); @@ -145,7 +147,7 @@ int main(int argc, char *argv[]) { }); } - auto scene = Scene::create(); + auto scene = makeShared(); scene->setBackgroundColor(Color(0.12f, 0.12f, 0.16f, 1.0f)); if (win) { scene->setViewportSize(static_cast(win->width()), @@ -163,7 +165,6 @@ int main(int argc, char *argv[]) { cameraService->applyViewportAdapter(); } - createSceneGraph(scene.get()); app.enterScene(scene); std::cout << "\nControls:" << std::endl; diff --git a/examples/hello_module/main.cpp b/examples/hello_module/main.cpp index 0dea10b..1496202 100644 --- a/examples/hello_module/main.cpp +++ b/examples/hello_module/main.cpp @@ -1,12 +1,7 @@ #include "hello_module.h" -#include -#include -#include -#include -#include +#include #include - using namespace extra2d; class HelloScene : public Scene { @@ -18,7 +13,7 @@ public: std::cout << "HelloScene entered" << std::endl; setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f)); - auto *hello = Application::get().get(); + auto hello = Application::get().get(); if (hello) { std::cout << "Scene calling HelloModule from onEnter..." << std::endl; hello->sayHello(); @@ -44,13 +39,6 @@ private: }; int main(int argc, char *argv[]) { - (void)argc; - (void)argv; - - std::cout << "=== Hello Module Example ===" << std::endl; - std::cout << "This example demonstrates how to create a custom module" - << std::endl; - std::cout << "" << std::endl; Application &app = Application::get(); @@ -71,21 +59,9 @@ int main(int argc, char *argv[]) { return 1; } - std::cout << "" << std::endl; - std::cout << "Application initialized successfully" << std::endl; - std::cout << "" << std::endl; - auto scene = HelloScene::create(); app.enterScene(scene); - - std::cout << "Starting main loop..." << std::endl; - std::cout << "Press ESC or close window to exit" << std::endl; - std::cout << "" << std::endl; - app.run(); - - std::cout << "Application shutting down..." << std::endl; app.shutdown(); - std::cout << "Application shutdown complete" << std::endl; return 0; } diff --git a/examples/text_rendering/main.cpp b/examples/text_rendering/main.cpp index e41671b..ce82b0c 100644 --- a/examples/text_rendering/main.cpp +++ b/examples/text_rendering/main.cpp @@ -6,15 +6,7 @@ * 此示例不依赖任何特定渲染后端(如 OpenGL) */ -#include #include -#include -#include -#include -#include -#include -#include -#include #include using namespace extra2d; @@ -103,9 +95,7 @@ public: // 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新 } - void setRenderer(RenderBackend* renderer) { - renderer_ = renderer; - } + void setRenderer(RenderBackend *renderer) { renderer_ = renderer; } private: void renderText(RenderBackend &renderer, const std::string &text, float x, @@ -119,7 +109,7 @@ private: } Ptr font_; - RenderBackend* renderer_ = nullptr; + RenderBackend *renderer_ = nullptr; }; int main(int argc, char *argv[]) { @@ -170,7 +160,7 @@ int main(int argc, char *argv[]) { } // 获取渲染器 - RenderBackend* renderer = app.renderer(); + RenderBackend *renderer = app.renderer(); // 创建并配置场景 auto scene = makeShared(); diff --git a/xmake/engine.lua b/xmake/engine.lua index 96981bd..3b692c3 100644 --- a/xmake/engine.lua +++ b/xmake/engine.lua @@ -34,6 +34,8 @@ function define_extra2d_engine() -- 渲染后端源文件 local render_backend = get_render_backend() + -- 图形后端工厂(始终编译) + add_files("Extra2D/src/graphics/backends/backend_factory.cpp") if render_backend == "vulkan" then add_files("Extra2D/src/graphics/backends/vulkan/*.cpp") add_defines("E2D_BACKEND_VULKAN")