refactor(图形后端): 重构图形后端系统为基于工厂的注册机制
- 移除BackendType枚举,改为使用字符串标识后端类型 - 实现图形后端工厂类,支持动态注册和创建后端 - 添加自动兼容性检查功能,根据窗口后端选择兼容的渲染器 - 移除WindowConfigData结构,简化窗口创建接口 - 更新示例代码以使用新的后端系统 - 添加OpenGL和Vulkan后端自动注册实现 - 清理无用代码和过时接口
This commit is contained in:
parent
583e866861
commit
8e06bb0adb
|
|
@ -1,79 +1,124 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/graphics/core/render_backend.h>
|
||||||
#include <extra2d/core/smart_ptr.h>
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
namespace graphics {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染后端类型枚举
|
* @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 后端工厂类,用于创建渲染后端实例
|
|
||||||
*/
|
*/
|
||||||
class BackendFactory {
|
class BackendFactory {
|
||||||
public:
|
public:
|
||||||
/**
|
using BackendFn = std::function<UniquePtr<RenderBackend>()>;
|
||||||
* @brief 获取后端工厂单例
|
|
||||||
* @return 后端工厂实例引用
|
|
||||||
*/
|
|
||||||
static BackendFactory& getInstance();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建渲染后端
|
* @brief 注册图形后端
|
||||||
* @param type 后端类型
|
* @param name 后端名称
|
||||||
* @return 渲染后端实例
|
* @param backend 后端创建函数
|
||||||
|
* @param windowBackends 支持的窗口后端名称列表
|
||||||
*/
|
*/
|
||||||
UniquePtr<RenderBackend> createBackend(BackendType type);
|
static void reg(const std::string &name, BackendFn backend,
|
||||||
|
const std::vector<std::string> &windowBackends = {});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建渲染后端实例
|
||||||
|
* @param name 后端名称
|
||||||
|
* @return 渲染后端实例,如果后端不存在返回 nullptr
|
||||||
|
*/
|
||||||
|
static UniquePtr<RenderBackend> createBackend(const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建默认渲染后端
|
* @brief 创建默认渲染后端
|
||||||
* @return 默认渲染后端实例
|
* @return 默认渲染后端实例
|
||||||
*/
|
*/
|
||||||
UniquePtr<RenderBackend> createDefaultBackend();
|
static UniquePtr<RenderBackend> createDefaultBackend();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 检查后端是否可用
|
* @brief 创建与指定窗口后端兼容的渲染后端
|
||||||
* @param type 后端类型
|
* @param windowBackend 窗口后端名称
|
||||||
* @return 可用返回true,否则返回false
|
* @return 兼容的渲染后端实例
|
||||||
*/
|
*/
|
||||||
bool isBackendAvailable(BackendType type) const;
|
static UniquePtr<RenderBackend>
|
||||||
|
createBackendForWindow(const std::string &windowBackend);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取当前平台推荐的后端类型
|
* @brief 获取所有已注册的后端名称
|
||||||
* @return 推荐的后端类型
|
|
||||||
*/
|
*/
|
||||||
BackendType getRecommendedBackend() const;
|
static std::vector<std::string> backends();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取后端类型名称
|
* @brief 检查后端是否存在
|
||||||
* @param type 后端类型
|
|
||||||
* @return 后端类型名称字符串
|
|
||||||
*/
|
*/
|
||||||
const char* getBackendName(BackendType type) const;
|
static bool has(const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 从名称解析后端类型
|
* @brief 获取推荐的后端名称
|
||||||
* @param name 后端类型名称
|
* @return 推荐的后端名称
|
||||||
* @return 后端类型,如果未知则返回OpenGL
|
|
||||||
*/
|
*/
|
||||||
BackendType parseBackendType(const char* name) const;
|
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<std::string>
|
||||||
|
getSupportedWindowBackends(const std::string &graphicsBackend);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BackendFactory() = default;
|
struct BackendEntry {
|
||||||
~BackendFactory() = default;
|
BackendFn createFn;
|
||||||
BackendFactory(const BackendFactory&) = delete;
|
std::vector<std::string> windowBackends;
|
||||||
BackendFactory& operator=(const BackendFactory&) = delete;
|
};
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, BackendEntry> ®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<RendererClass>(); \
|
||||||
|
}, \
|
||||||
|
windowBackends); \
|
||||||
|
} \
|
||||||
|
} e2d_graphics_backend_reg_##name; \
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace graphics
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,6 @@ class Texture;
|
||||||
class FontAtlas;
|
class FontAtlas;
|
||||||
class Shader;
|
class Shader;
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// 渲染后端类型
|
|
||||||
// ============================================================================
|
|
||||||
enum class BackendType {
|
|
||||||
OpenGL,
|
|
||||||
// Vulkan,
|
|
||||||
// Metal,
|
|
||||||
// D3D11,
|
|
||||||
// D3D12
|
|
||||||
};
|
|
||||||
|
|
||||||
// BlendMode 定义在 pipeline.h 中
|
// BlendMode 定义在 pipeline.h 中
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -131,11 +120,6 @@ public:
|
||||||
};
|
};
|
||||||
virtual Stats getStats() const = 0;
|
virtual Stats getStats() const = 0;
|
||||||
virtual void resetStats() = 0;
|
virtual void resetStats() = 0;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// 工厂方法
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
static UniquePtr<RenderBackend> create(BackendType type);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,14 @@ namespace extra2d {
|
||||||
* @brief 渲染模块配置结构
|
* @brief 渲染模块配置结构
|
||||||
*/
|
*/
|
||||||
struct RenderCfg {
|
struct RenderCfg {
|
||||||
BackendType backend;
|
std::string backend;
|
||||||
int targetFPS;
|
int targetFPS;
|
||||||
bool vsync;
|
bool vsync;
|
||||||
int multisamples;
|
int multisamples;
|
||||||
int priority;
|
int priority;
|
||||||
|
|
||||||
RenderCfg()
|
RenderCfg()
|
||||||
: backend(BackendType::OpenGL)
|
: backend("")
|
||||||
, targetFPS(60)
|
, targetFPS(60)
|
||||||
, vsync(true)
|
, vsync(true)
|
||||||
, multisamples(0)
|
, multisamples(0)
|
||||||
|
|
@ -29,7 +29,7 @@ struct RenderCfg {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染模块
|
* @brief 渲染模块
|
||||||
* 管理渲染后端
|
* 管理渲染后端,自动根据窗口后端选择兼容的渲染器
|
||||||
*/
|
*/
|
||||||
class RenderModule : public Module {
|
class RenderModule : public Module {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/platform/iwindow.h>
|
|
||||||
#include <extra2d/platform/iinput.h>
|
#include <extra2d/platform/iinput.h>
|
||||||
|
#include <extra2d/platform/iwindow.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
namespace platform {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 平台后端工厂
|
* @brief 平台后端工厂
|
||||||
|
|
@ -25,21 +26,21 @@ public:
|
||||||
* @param win 窗口创建函数
|
* @param win 窗口创建函数
|
||||||
* @param in 输入创建函数
|
* @param in 输入创建函数
|
||||||
*/
|
*/
|
||||||
static void reg(const std::string& name, WindowFn win, InputFn in);
|
static void reg(const std::string &name, WindowFn win, InputFn in);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建窗口实例
|
* @brief 创建窗口实例
|
||||||
* @param name 后端名称
|
* @param name 后端名称
|
||||||
* @return 窗口实例,如果后端不存在返回 nullptr
|
* @return 窗口实例,如果后端不存在返回 nullptr
|
||||||
*/
|
*/
|
||||||
static UniquePtr<IWindow> createWindow(const std::string& name);
|
static UniquePtr<IWindow> createWindow(const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建输入实例
|
* @brief 创建输入实例
|
||||||
* @param name 后端名称
|
* @param name 后端名称
|
||||||
* @return 输入实例,如果后端不存在返回 nullptr
|
* @return 输入实例,如果后端不存在返回 nullptr
|
||||||
*/
|
*/
|
||||||
static UniquePtr<IInput> createInput(const std::string& name);
|
static UniquePtr<IInput> createInput(const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取所有已注册的后端名称
|
* @brief 获取所有已注册的后端名称
|
||||||
|
|
@ -49,7 +50,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief 检查后端是否存在
|
* @brief 检查后端是否存在
|
||||||
*/
|
*/
|
||||||
static bool has(const std::string& name);
|
static bool has(const std::string &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct BackendEntry {
|
struct BackendEntry {
|
||||||
|
|
@ -57,7 +58,7 @@ private:
|
||||||
InputFn inputFn;
|
InputFn inputFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unordered_map<std::string, BackendEntry>& registry();
|
static std::unordered_map<std::string, BackendEntry> ®istry();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -69,20 +70,19 @@ private:
|
||||||
*/
|
*/
|
||||||
#define E2D_REG_BACKEND(name, WinClass, InClass) \
|
#define E2D_REG_BACKEND(name, WinClass, InClass) \
|
||||||
namespace { \
|
namespace { \
|
||||||
__attribute__((used)) \
|
__attribute__((used)) static struct E2D_BACKEND_REG_##name { \
|
||||||
static struct E2D_BACKEND_REG_##name { \
|
|
||||||
E2D_BACKEND_REG_##name() { \
|
E2D_BACKEND_REG_##name() { \
|
||||||
::extra2d::BackendFactory::reg( \
|
::extra2d::platform::BackendFactory::reg( \
|
||||||
#name, \
|
#name, \
|
||||||
[]() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \
|
[]() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \
|
||||||
return ::extra2d::makeUnique<WinClass>(); \
|
return ::extra2d::makeUnique<WinClass>(); \
|
||||||
}, \
|
}, \
|
||||||
[]() -> ::extra2d::UniquePtr<::extra2d::IInput> { \
|
[]() -> ::extra2d::UniquePtr<::extra2d::IInput> { \
|
||||||
return ::extra2d::makeUnique<InClass>(); \
|
return ::extra2d::makeUnique<InClass>(); \
|
||||||
} \
|
}); \
|
||||||
); \
|
|
||||||
} \
|
} \
|
||||||
} e2d_backend_reg_##name; \
|
} e2d_backend_reg_##name; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace platform
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/core/math_types.h>
|
#include <extra2d/core/math_types.h>
|
||||||
#include <extra2d/platform/window_config.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -33,10 +32,13 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建窗口
|
* @brief 创建窗口
|
||||||
* @param cfg 窗口配置
|
* @param title 窗口标题
|
||||||
|
* @param width 窗口宽度
|
||||||
|
* @param height 窗口高度
|
||||||
|
* @param vsync 是否启用垂直同步
|
||||||
* @return 创建是否成功
|
* @return 创建是否成功
|
||||||
*/
|
*/
|
||||||
virtual bool create(const WindowConfigData& cfg) = 0;
|
virtual bool create(const std::string& title, int width, int height, bool vsync = true) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 销毁窗口
|
* @brief 销毁窗口
|
||||||
|
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/core/math_types.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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<float>(width) / static_cast<float>(height); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 检查是否为全屏模式
|
|
||||||
* @return 如果是全屏模式返回 true
|
|
||||||
*/
|
|
||||||
bool isFullscreen() const { return mode == WindowMode::Fullscreen; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 检查是否为无边框模式
|
|
||||||
* @return 如果是无边框模式返回 true
|
|
||||||
*/
|
|
||||||
bool isBorderless() const { return mode == WindowMode::Borderless || borderless; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <extra2d/core/module.h>
|
#include <extra2d/core/module.h>
|
||||||
#include <extra2d/platform/iwindow.h>
|
#include <extra2d/platform/iwindow.h>
|
||||||
#include <extra2d/platform/window_config.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -15,14 +14,13 @@ struct WindowCfg {
|
||||||
std::string title;
|
std::string title;
|
||||||
int w;
|
int w;
|
||||||
int h;
|
int h;
|
||||||
WindowMode mode;
|
|
||||||
bool vsync;
|
bool vsync;
|
||||||
int priority;
|
int priority;
|
||||||
std::string backend;
|
std::string backend;
|
||||||
|
|
||||||
WindowCfg()
|
WindowCfg()
|
||||||
: title("Extra2D"), w(1280), h(720), mode(WindowMode::Windowed),
|
: title("Extra2D"), w(1280), h(720), vsync(true), priority(0),
|
||||||
vsync(true), priority(0), backend("sdl2") {}
|
backend("sdl2") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,11 +52,16 @@ public:
|
||||||
*/
|
*/
|
||||||
IWindow *win() const { return win_.get(); }
|
IWindow *win() const { return win_.get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取窗口后端名称
|
||||||
|
* @return 窗口后端名称
|
||||||
|
*/
|
||||||
|
const std::string &getWindowBackend() const { return cfg_.backend; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WindowCfg cfg_;
|
WindowCfg cfg_;
|
||||||
UniquePtr<IWindow> win_;
|
UniquePtr<IWindow> win_;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
bool sdlInited_ = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -1,127 +1,136 @@
|
||||||
#include <extra2d/graphics/backends/backend_factory.h>
|
#include <extra2d/graphics/backends/backend_factory.h>
|
||||||
|
|
||||||
// 条件编译包含对应后端实现
|
|
||||||
#ifdef E2D_BACKEND_OPENGL
|
|
||||||
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef E2D_BACKEND_VULKAN
|
|
||||||
#include <extra2d/graphics/backends/vulkan/vk_renderer.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <extra2d/utils/logger.h>
|
#include <extra2d/utils/logger.h>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
namespace graphics {
|
||||||
|
|
||||||
BackendFactory& BackendFactory::getInstance() {
|
std::unordered_map<std::string, BackendFactory::BackendEntry>& BackendFactory::registry() {
|
||||||
static BackendFactory instance;
|
static std::unordered_map<std::string, BackendEntry> reg;
|
||||||
return instance;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePtr<RenderBackend> BackendFactory::createBackend(BackendType type) {
|
void BackendFactory::reg(const std::string& name, BackendFn backend,
|
||||||
switch (type) {
|
const std::vector<std::string>& windowBackends) {
|
||||||
#ifdef E2D_BACKEND_OPENGL
|
registry()[name] = {backend, windowBackends};
|
||||||
case BackendType::OpenGL:
|
E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})",
|
||||||
E2D_LOG_INFO("Creating OpenGL render backend");
|
name, windowBackends.size());
|
||||||
return makeUnique<GLRenderer>();
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef E2D_BACKEND_VULKAN
|
UniquePtr<RenderBackend> BackendFactory::createBackend(const std::string& name) {
|
||||||
case BackendType::Vulkan:
|
auto& reg = registry();
|
||||||
E2D_LOG_INFO("Creating Vulkan render backend");
|
auto it = reg.find(name);
|
||||||
return makeUnique<VulkanRenderer>();
|
if (it != reg.end() && it->second.createFn) {
|
||||||
#endif
|
E2D_LOG_INFO("Creating graphics backend: {}", name);
|
||||||
|
return it->second.createFn();
|
||||||
default:
|
|
||||||
E2D_LOG_ERROR("Unsupported render backend type: {}", static_cast<int>(type));
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
E2D_LOG_ERROR("Graphics backend '{}' not found", name);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
||||||
BackendType recommended = getRecommendedBackend();
|
std::string recommended = getRecommendedBackend();
|
||||||
|
if (recommended.empty()) {
|
||||||
|
E2D_LOG_ERROR("No graphics backend available");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return createBackend(recommended);
|
return createBackend(recommended);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackendFactory::isBackendAvailable(BackendType type) const {
|
UniquePtr<RenderBackend> BackendFactory::createBackendForWindow(const std::string& windowBackend) {
|
||||||
switch (type) {
|
std::string recommended = getRecommendedBackendForWindow(windowBackend);
|
||||||
#ifdef E2D_BACKEND_OPENGL
|
if (recommended.empty()) {
|
||||||
case BackendType::OpenGL:
|
E2D_LOG_ERROR("No compatible graphics backend for window backend: {}", windowBackend);
|
||||||
return true;
|
return nullptr;
|
||||||
#endif
|
}
|
||||||
|
return createBackend(recommended);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef E2D_BACKEND_VULKAN
|
std::vector<std::string> BackendFactory::backends() {
|
||||||
case BackendType::Vulkan:
|
std::vector<std::string> result;
|
||||||
return true;
|
for (const auto& pair : registry()) {
|
||||||
#endif
|
result.push_back(pair.first);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
bool BackendFactory::has(const std::string& name) {
|
||||||
|
return registry().find(name) != registry().end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BackendFactory::getRecommendedBackend() {
|
||||||
|
auto& reg = registry();
|
||||||
|
|
||||||
|
static const std::vector<std::string> 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<std::string> 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& windowBackends = it->second.windowBackends;
|
||||||
|
if (windowBackends.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& wb : windowBackends) {
|
||||||
|
if (wb == windowBackend) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendType BackendFactory::getRecommendedBackend() const {
|
std::vector<std::string> BackendFactory::getSupportedWindowBackends(const std::string& graphicsBackend) {
|
||||||
// 平台特定的默认后端选择
|
auto& reg = registry();
|
||||||
// 优先级:Vulkan > OpenGL
|
auto it = reg.find(graphicsBackend);
|
||||||
|
if (it != reg.end()) {
|
||||||
#ifdef E2D_BACKEND_VULKAN
|
return it->second.windowBackends;
|
||||||
return BackendType::Vulkan;
|
}
|
||||||
#endif
|
return {};
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace graphics
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
|
||||||
|
#include <extra2d/graphics/backends/backend_factory.h>
|
||||||
|
|
||||||
|
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<RenderBackend> {
|
||||||
|
return makeUnique<GLRenderer>();
|
||||||
|
},
|
||||||
|
{"sdl2", "glfw"}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct OpenGLBackendAutoReg {
|
||||||
|
OpenGLBackendAutoReg() {
|
||||||
|
initOpenGLBackend();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static OpenGLBackendAutoReg s_openglAutoReg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include <extra2d/graphics/backends/vulkan/vk_renderer.h>
|
||||||
|
#include <extra2d/graphics/backends/backend_factory.h>
|
||||||
|
|
||||||
|
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<RenderBackend> {
|
||||||
|
return makeUnique<VulkanRenderer>();
|
||||||
|
},
|
||||||
|
{"sdl2", "glfw"}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct VulkanBackendAutoReg {
|
||||||
|
VulkanBackendAutoReg() {
|
||||||
|
initVulkanBackend();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static VulkanBackendAutoReg s_vulkanAutoReg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
|
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 创建渲染后端实例
|
|
||||||
*
|
|
||||||
* 根据指定的后端类型创建对应的渲染后端实例,
|
|
||||||
* 目前支持OpenGL后端
|
|
||||||
*
|
|
||||||
* @param type 渲染后端类型(如OpenGL)
|
|
||||||
* @return 成功返回渲染后端的唯一指针,不支持的类型返回nullptr
|
|
||||||
*/
|
|
||||||
UniquePtr<RenderBackend> RenderBackend::create(BackendType type) {
|
|
||||||
switch (type) {
|
|
||||||
case BackendType::OpenGL:
|
|
||||||
return makeUnique<GLRenderer>();
|
|
||||||
default:
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include <extra2d/graphics/core/render_module.h>
|
#include <extra2d/graphics/core/render_module.h>
|
||||||
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
|
#include <extra2d/graphics/backends/backend_factory.h>
|
||||||
#include <extra2d/graphics/backends/opengl/gl_shader.h>
|
#include <extra2d/graphics/backends/opengl/gl_shader.h>
|
||||||
#include <extra2d/graphics/shader/shader_manager.h>
|
#include <extra2d/graphics/shader/shader_manager.h>
|
||||||
#include <extra2d/core/registry.h>
|
#include <extra2d/core/registry.h>
|
||||||
|
|
@ -11,6 +11,16 @@
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
// 前向声明后端初始化函数
|
||||||
|
namespace graphics {
|
||||||
|
#ifdef E2D_BACKEND_OPENGL
|
||||||
|
void initOpenGLBackend();
|
||||||
|
#endif
|
||||||
|
#ifdef E2D_BACKEND_VULKAN
|
||||||
|
void initVulkanBackend();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
RenderModule::RenderModule(std::function<void(RenderCfg&)> configFn) {
|
RenderModule::RenderModule(std::function<void(RenderCfg&)> configFn) {
|
||||||
configFn(cfg_);
|
configFn(cfg_);
|
||||||
}
|
}
|
||||||
|
|
@ -33,13 +43,20 @@ static std::string getExecutableDir() {
|
||||||
bool RenderModule::init() {
|
bool RenderModule::init() {
|
||||||
if (initialized_) return true;
|
if (initialized_) return true;
|
||||||
|
|
||||||
// 获取WindowModule依赖
|
|
||||||
auto* winMod = Registry::instance().get<WindowModule>();
|
auto* winMod = Registry::instance().get<WindowModule>();
|
||||||
if (!winMod || !winMod->win()) {
|
if (!winMod || !winMod->win()) {
|
||||||
|
E2D_LOG_ERROR("WindowModule not available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化ShaderManager
|
// 初始化图形后端(注册到工厂)
|
||||||
|
#ifdef E2D_BACKEND_OPENGL
|
||||||
|
graphics::initOpenGLBackend();
|
||||||
|
#endif
|
||||||
|
#ifdef E2D_BACKEND_VULKAN
|
||||||
|
graphics::initVulkanBackend();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!ShaderManager::getInstance().isInitialized()) {
|
if (!ShaderManager::getInstance().isInitialized()) {
|
||||||
auto factory = makeShared<GLShaderFactory>();
|
auto factory = makeShared<GLShaderFactory>();
|
||||||
std::string shaderDir = getExecutableDir() + "shaders/";
|
std::string shaderDir = getExecutableDir() + "shaders/";
|
||||||
|
|
@ -49,18 +66,31 @@ bool RenderModule::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建渲染后端
|
std::string windowBackend = winMod->getWindowBackend();
|
||||||
renderer_ = RenderBackend::create(cfg_.backend);
|
|
||||||
|
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_) {
|
if (!renderer_) {
|
||||||
|
E2D_LOG_ERROR("Failed to create render backend");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化渲染器
|
|
||||||
if (!renderer_->init(winMod->win())) {
|
if (!renderer_->init(winMod->win())) {
|
||||||
|
E2D_LOG_ERROR("Failed to initialize render backend");
|
||||||
renderer_.reset();
|
renderer_.reset();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_LOG_INFO("Render module initialized successfully");
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <extra2d/platform/backend_factory.h>
|
#include <extra2d/platform/backend_factory.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
namespace platform {
|
||||||
|
|
||||||
std::unordered_map<std::string, BackendFactory::BackendEntry>& BackendFactory::registry() {
|
std::unordered_map<std::string, BackendFactory::BackendEntry>& BackendFactory::registry() {
|
||||||
static std::unordered_map<std::string, BackendEntry> reg;
|
static std::unordered_map<std::string, BackendEntry> reg;
|
||||||
|
|
@ -41,4 +42,5 @@ bool BackendFactory::has(const std::string& name) {
|
||||||
return registry().find(name) != registry().end();
|
return registry().find(name) != registry().end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace platform
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <extra2d/platform/backend_factory.h>
|
#include <extra2d/platform/backend_factory.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
namespace platform {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static bool s_glfwBackendRegistered = false;
|
static bool s_glfwBackendRegistered = false;
|
||||||
|
|
@ -25,4 +26,5 @@ void initGLFWBackend() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace platform
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,11 @@ GLFWWindow::~GLFWWindow() {
|
||||||
destroy();
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLFWWindow::create(const WindowConfigData& cfg) {
|
bool GLFWWindow::create(const std::string& title, int width, int height, bool vsync) {
|
||||||
if (!initGLFW()) {
|
if (!initGLFW()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置 OpenGL ES 3.2 上下文
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
|
|
@ -26,44 +25,21 @@ bool GLFWWindow::create(const WindowConfigData& cfg) {
|
||||||
glfwWindowHint(GLFW_STENCIL_BITS, 8);
|
glfwWindowHint(GLFW_STENCIL_BITS, 8);
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
// Switch 平台强制全屏
|
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
||||||
fullscreen_ = true;
|
fullscreen_ = true;
|
||||||
#else
|
#else
|
||||||
// 桌面平台配置
|
|
||||||
if (cfg.resizable) {
|
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
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;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (cfg.multisamples > 0) {
|
|
||||||
glfwWindowHint(GLFW_SAMPLES, cfg.multisamples);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建窗口
|
|
||||||
GLFWmonitor* monitor = nullptr;
|
GLFWmonitor* monitor = nullptr;
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
monitor = glfwGetPrimaryMonitor();
|
monitor = glfwGetPrimaryMonitor();
|
||||||
#endif
|
#endif
|
||||||
if (fullscreen_ && !monitor) {
|
|
||||||
monitor = glfwGetPrimaryMonitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwWindow_ = glfwCreateWindow(
|
glfwWindow_ = glfwCreateWindow(
|
||||||
cfg.width, cfg.height,
|
width, height,
|
||||||
cfg.title.c_str(),
|
title.c_str(),
|
||||||
monitor,
|
monitor,
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
|
|
@ -74,7 +50,6 @@ bool GLFWWindow::create(const WindowConfigData& cfg) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 窗口居中(非全屏模式下)
|
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
if (!fullscreen_ && !monitor) {
|
if (!fullscreen_ && !monitor) {
|
||||||
GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor();
|
GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor();
|
||||||
|
|
@ -83,8 +58,8 @@ bool GLFWWindow::create(const WindowConfigData& cfg) {
|
||||||
if (mode) {
|
if (mode) {
|
||||||
int screenWidth = mode->width;
|
int screenWidth = mode->width;
|
||||||
int screenHeight = mode->height;
|
int screenHeight = mode->height;
|
||||||
int windowX = (screenWidth - cfg.width) / 2;
|
int windowX = (screenWidth - width) / 2;
|
||||||
int windowY = (screenHeight - cfg.height) / 2;
|
int windowY = (screenHeight - height) / 2;
|
||||||
glfwSetWindowPos(glfwWindow_, windowX, windowY);
|
glfwSetWindowPos(glfwWindow_, windowX, windowY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +68,6 @@ bool GLFWWindow::create(const WindowConfigData& cfg) {
|
||||||
|
|
||||||
glfwMakeContextCurrent(glfwWindow_);
|
glfwMakeContextCurrent(glfwWindow_);
|
||||||
|
|
||||||
// 初始化 GLAD
|
|
||||||
if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) {
|
if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) {
|
||||||
E2D_LOG_ERROR("Failed to initialize GLAD GLES2");
|
E2D_LOG_ERROR("Failed to initialize GLAD GLES2");
|
||||||
glfwDestroyWindow(glfwWindow_);
|
glfwDestroyWindow(glfwWindow_);
|
||||||
|
|
@ -102,15 +76,12 @@ bool GLFWWindow::create(const WindowConfigData& cfg) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置垂直同步
|
glfwSwapInterval(vsync ? 1 : 0);
|
||||||
glfwSwapInterval(cfg.vsync ? 1 : 0);
|
vsync_ = vsync;
|
||||||
vsync_ = cfg.vsync;
|
|
||||||
|
|
||||||
// 获取实际窗口大小
|
|
||||||
glfwGetWindowSize(glfwWindow_, &width_, &height_);
|
glfwGetWindowSize(glfwWindow_, &width_, &height_);
|
||||||
updateContentScale();
|
updateContentScale();
|
||||||
|
|
||||||
// 设置回调函数
|
|
||||||
glfwSetWindowUserPointer(glfwWindow_, this);
|
glfwSetWindowUserPointer(glfwWindow_, this);
|
||||||
glfwSetFramebufferSizeCallback(glfwWindow_, framebufferSizeCallback);
|
glfwSetFramebufferSizeCallback(glfwWindow_, framebufferSizeCallback);
|
||||||
glfwSetWindowCloseCallback(glfwWindow_, windowCloseCallback);
|
glfwSetWindowCloseCallback(glfwWindow_, windowCloseCallback);
|
||||||
|
|
@ -122,7 +93,6 @@ bool GLFWWindow::create(const WindowConfigData& cfg) {
|
||||||
glfwSetKeyCallback(glfwWindow_, keyCallback);
|
glfwSetKeyCallback(glfwWindow_, keyCallback);
|
||||||
glfwSetJoystickCallback(joystickCallback);
|
glfwSetJoystickCallback(joystickCallback);
|
||||||
|
|
||||||
// 创建输入系统
|
|
||||||
input_ = makeUnique<GLFWInput>();
|
input_ = makeUnique<GLFWInput>();
|
||||||
input_->setWindow(glfwWindow_);
|
input_->setWindow(glfwWindow_);
|
||||||
input_->init();
|
input_->init();
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public:
|
||||||
GLFWWindow();
|
GLFWWindow();
|
||||||
~GLFWWindow() override;
|
~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 destroy() override;
|
||||||
|
|
||||||
void poll() override;
|
void poll() override;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <extra2d/platform/backend_factory.h>
|
#include <extra2d/platform/backend_factory.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
namespace platform {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static bool s_sdl2BackendRegistered = false;
|
static bool s_sdl2BackendRegistered = false;
|
||||||
|
|
@ -25,4 +26,5 @@ void initSDL2Backend() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace platform
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -15,27 +15,15 @@ SDL2Window::~SDL2Window() {
|
||||||
destroy();
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDL2Window::create(const WindowConfigData& cfg) {
|
bool SDL2Window::create(const std::string& title, int width, int height, bool vsync) {
|
||||||
if (!initSDL()) {
|
if (!initSDL()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
|
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
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
|
#endif
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
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_DEPTH_SIZE, 24);
|
||||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
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(
|
sdlWindow_ = SDL_CreateWindow(
|
||||||
cfg.title.c_str(),
|
title.c_str(),
|
||||||
x, y,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
cfg.width, cfg.height,
|
width, height,
|
||||||
flags
|
flags
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -90,11 +66,11 @@ bool SDL2Window::create(const WindowConfigData& cfg) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(cfg.vsync ? 1 : 0);
|
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
|
||||||
|
|
||||||
SDL_GetWindowSize(sdlWindow_, &width_, &height_);
|
SDL_GetWindowSize(sdlWindow_, &width_, &height_);
|
||||||
fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
||||||
vsync_ = cfg.vsync;
|
vsync_ = vsync;
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
initCursors();
|
initCursors();
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public:
|
||||||
SDL2Window();
|
SDL2Window();
|
||||||
~SDL2Window() override;
|
~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 destroy() override;
|
||||||
|
|
||||||
void poll() override;
|
void poll() override;
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,13 @@
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
// 前向声明后端初始化函数
|
// 前向声明后端初始化函数
|
||||||
|
namespace platform {
|
||||||
#if defined(E2D_BACKEND_SDL2)
|
#if defined(E2D_BACKEND_SDL2)
|
||||||
void initSDL2Backend();
|
void initSDL2Backend();
|
||||||
#elif defined(E2D_BACKEND_GLFW)
|
#elif defined(E2D_BACKEND_GLFW)
|
||||||
void initGLFWBackend();
|
void initGLFWBackend();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
WindowModule::WindowModule(std::function<void(WindowCfg&)> configFn) {
|
WindowModule::WindowModule(std::function<void(WindowCfg&)> configFn) {
|
||||||
configFn(cfg_);
|
configFn(cfg_);
|
||||||
|
|
@ -29,39 +31,27 @@ WindowModule::~WindowModule() {
|
||||||
bool WindowModule::init() {
|
bool WindowModule::init() {
|
||||||
if (initialized_) return true;
|
if (initialized_) return true;
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
|
||||||
cfg_.mode = WindowMode::Fullscreen;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 初始化后端(注册到工厂)
|
// 初始化后端(注册到工厂)
|
||||||
#if defined(E2D_BACKEND_SDL2)
|
#if defined(E2D_BACKEND_SDL2)
|
||||||
initSDL2Backend();
|
platform::initSDL2Backend();
|
||||||
#elif defined(E2D_BACKEND_GLFW)
|
#elif defined(E2D_BACKEND_GLFW)
|
||||||
initGLFWBackend();
|
platform::initGLFWBackend();
|
||||||
#else
|
#else
|
||||||
#error "No window backend defined"
|
#error "No window backend defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
E2D_LOG_INFO("Window backend initialized");
|
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);
|
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_) {
|
if (!win_) {
|
||||||
E2D_LOG_ERROR("Failed to create window backend: {}", cfg_.backend);
|
E2D_LOG_ERROR("Failed to create window backend: {}", cfg_.backend);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!win_->create(winCfg)) {
|
if (!win_->create(cfg_.title, cfg_.w, cfg_.h, cfg_.vsync)) {
|
||||||
E2D_LOG_ERROR("Failed to create window");
|
E2D_LOG_ERROR("Failed to create window");
|
||||||
shutdown();
|
shutdown();
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,27 @@
|
||||||
* @brief Extra2D 场景图测试示例
|
* @brief Extra2D 场景图测试示例
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/extra2d.h>
|
#include <extra2d/extra2d.h>
|
||||||
#include <extra2d/graphics/core/render_module.h>
|
|
||||||
#include <extra2d/platform/input_module.h>
|
|
||||||
#include <extra2d/platform/window_module.h>
|
|
||||||
#include <extra2d/services/camera_service.h>
|
|
||||||
#include <extra2d/services/event_service.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
||||||
void createSceneGraph(Scene *scene) {
|
/**
|
||||||
float width = scene->getWidth();
|
* @brief 基础场景类,演示场景图功能
|
||||||
float height = scene->getHeight();
|
*/
|
||||||
|
class BasicScene : public Scene {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 场景进入时初始化场景图
|
||||||
|
*/
|
||||||
|
void onEnter() override {
|
||||||
|
float width = getWidth();
|
||||||
|
float height = getHeight();
|
||||||
|
|
||||||
auto root = makeShared<Node>();
|
auto root = makeShared<Node>();
|
||||||
root->setName("Root");
|
root->setName("Root");
|
||||||
root->setPos(width / 2, height / 2);
|
root->setPos(width / 2, height / 2);
|
||||||
scene->addChild(root);
|
addChild(root);
|
||||||
|
|
||||||
auto parent1 = makeShared<Node>();
|
auto parent1 = makeShared<Node>();
|
||||||
parent1->setName("Parent1");
|
parent1->setName("Parent1");
|
||||||
|
|
@ -61,7 +63,8 @@ void createSceneGraph(Scene *scene) {
|
||||||
parent2->addChild(child2);
|
parent2->addChild(child2);
|
||||||
|
|
||||||
auto triangle = ShapeNode::createFilledTriangle(
|
auto triangle = ShapeNode::createFilledTriangle(
|
||||||
Vec2(0, -40), Vec2(-35, 30), Vec2(35, 30), Color(0.4f, 1.0f, 0.4f, 1.0f));
|
Vec2(0, -40), Vec2(-35, 30), Vec2(35, 30),
|
||||||
|
Color(0.4f, 1.0f, 0.4f, 1.0f));
|
||||||
triangle->setName("GreenTriangle");
|
triangle->setName("GreenTriangle");
|
||||||
child2->addChild(triangle);
|
child2->addChild(triangle);
|
||||||
|
|
||||||
|
|
@ -76,22 +79,19 @@ void createSceneGraph(Scene *scene) {
|
||||||
polygon->setName("PurplePolygon");
|
polygon->setName("PurplePolygon");
|
||||||
polygon->setPos(0, -150);
|
polygon->setPos(0, -150);
|
||||||
root->addChild(polygon);
|
root->addChild(polygon);
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "\n=== Scene Graph Structure ===" << std::endl;
|
/**
|
||||||
std::cout << "Scene (root)" << std::endl;
|
* @brief 场景退出时清理资源
|
||||||
std::cout << " └── Root (center)" << std::endl;
|
*/
|
||||||
std::cout << " ├── Parent1 (left)" << std::endl;
|
void onExit() override { clearChildren(); }
|
||||||
std::cout << " │ ├── RedRect (100x100)" << std::endl;
|
|
||||||
std::cout << " │ └── Child1 (rotated 45, scaled 0.5)" << std::endl;
|
/**
|
||||||
std::cout << " │ └── OrangeRect (60x60)" << std::endl;
|
* @brief 自定义渲染逻辑
|
||||||
std::cout << " ├── Parent2 (right)" << std::endl;
|
* @param renderer 渲染后端
|
||||||
std::cout << " │ ├── BlueCircle (radius 60)" << std::endl;
|
*/
|
||||||
std::cout << " │ └── Child2 (below)" << std::endl;
|
void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); }
|
||||||
std::cout << " │ └── GreenTriangle" << std::endl;
|
};
|
||||||
std::cout << " ├── BottomLine" << std::endl;
|
|
||||||
std::cout << " └── PurplePolygon (pentagon)" << std::endl;
|
|
||||||
std::cout << "=============================\n" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
(void)argc;
|
(void)argc;
|
||||||
|
|
@ -101,7 +101,6 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
Application &app = Application::get();
|
Application &app = Application::get();
|
||||||
|
|
||||||
// 注册模块(按优先级顺序)
|
|
||||||
app.use<WindowModule>([](auto &cfg) {
|
app.use<WindowModule>([](auto &cfg) {
|
||||||
cfg.w = 1280;
|
cfg.w = 1280;
|
||||||
cfg.h = 720;
|
cfg.h = 720;
|
||||||
|
|
@ -109,7 +108,10 @@ int main(int argc, char *argv[]) {
|
||||||
cfg.backend = "glfw";
|
cfg.backend = "glfw";
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use<RenderModule>([](auto &cfg) { cfg.priority = 10; });
|
app.use<RenderModule>([](auto &cfg) {
|
||||||
|
cfg.priority = 10;
|
||||||
|
cfg.backend = "opengl";
|
||||||
|
});
|
||||||
|
|
||||||
app.use<InputModule>([](auto &cfg) { cfg.priority = 20; });
|
app.use<InputModule>([](auto &cfg) { cfg.priority = 20; });
|
||||||
|
|
||||||
|
|
@ -145,7 +147,7 @@ int main(int argc, char *argv[]) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto scene = Scene::create();
|
auto scene = makeShared<BasicScene>();
|
||||||
scene->setBackgroundColor(Color(0.12f, 0.12f, 0.16f, 1.0f));
|
scene->setBackgroundColor(Color(0.12f, 0.12f, 0.16f, 1.0f));
|
||||||
if (win) {
|
if (win) {
|
||||||
scene->setViewportSize(static_cast<float>(win->width()),
|
scene->setViewportSize(static_cast<float>(win->width()),
|
||||||
|
|
@ -163,7 +165,6 @@ int main(int argc, char *argv[]) {
|
||||||
cameraService->applyViewportAdapter();
|
cameraService->applyViewportAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
createSceneGraph(scene.get());
|
|
||||||
app.enterScene(scene);
|
app.enterScene(scene);
|
||||||
|
|
||||||
std::cout << "\nControls:" << std::endl;
|
std::cout << "\nControls:" << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
#include "hello_module.h"
|
#include "hello_module.h"
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/extra2d.h>
|
||||||
#include <extra2d/graphics/core/render_module.h>
|
|
||||||
#include <extra2d/platform/window_module.h>
|
|
||||||
#include <extra2d/scene/scene.h>
|
|
||||||
#include <extra2d/services/scene_service.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
||||||
class HelloScene : public Scene {
|
class HelloScene : public Scene {
|
||||||
|
|
@ -18,7 +13,7 @@ public:
|
||||||
std::cout << "HelloScene entered" << std::endl;
|
std::cout << "HelloScene entered" << std::endl;
|
||||||
setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f));
|
setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f));
|
||||||
|
|
||||||
auto *hello = Application::get().get<HelloModule>();
|
auto hello = Application::get().get<HelloModule>();
|
||||||
if (hello) {
|
if (hello) {
|
||||||
std::cout << "Scene calling HelloModule from onEnter..." << std::endl;
|
std::cout << "Scene calling HelloModule from onEnter..." << std::endl;
|
||||||
hello->sayHello();
|
hello->sayHello();
|
||||||
|
|
@ -44,13 +39,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
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();
|
Application &app = Application::get();
|
||||||
|
|
||||||
|
|
@ -71,21 +59,9 @@ int main(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "" << std::endl;
|
|
||||||
std::cout << "Application initialized successfully" << std::endl;
|
|
||||||
std::cout << "" << std::endl;
|
|
||||||
|
|
||||||
auto scene = HelloScene::create();
|
auto scene = HelloScene::create();
|
||||||
app.enterScene(scene);
|
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();
|
app.run();
|
||||||
|
|
||||||
std::cout << "Application shutting down..." << std::endl;
|
|
||||||
app.shutdown();
|
app.shutdown();
|
||||||
std::cout << "Application shutdown complete" << std::endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,7 @@
|
||||||
* 此示例不依赖任何特定渲染后端(如 OpenGL)
|
* 此示例不依赖任何特定渲染后端(如 OpenGL)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/extra2d.h>
|
#include <extra2d/extra2d.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
|
||||||
#include <extra2d/graphics/core/render_module.h>
|
|
||||||
#include <extra2d/graphics/texture/font.h>
|
|
||||||
#include <extra2d/platform/input_module.h>
|
|
||||||
#include <extra2d/platform/window_module.h>
|
|
||||||
#include <extra2d/services/camera_service.h>
|
|
||||||
#include <extra2d/services/event_service.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
@ -103,9 +95,7 @@ public:
|
||||||
// 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新
|
// 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRenderer(RenderBackend* renderer) {
|
void setRenderer(RenderBackend *renderer) { renderer_ = renderer; }
|
||||||
renderer_ = renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderText(RenderBackend &renderer, const std::string &text, float x,
|
void renderText(RenderBackend &renderer, const std::string &text, float x,
|
||||||
|
|
@ -119,7 +109,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
Ptr<FontAtlas> font_;
|
Ptr<FontAtlas> font_;
|
||||||
RenderBackend* renderer_ = nullptr;
|
RenderBackend *renderer_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
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<TextRenderingScene>();
|
auto scene = makeShared<TextRenderingScene>();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ function define_extra2d_engine()
|
||||||
|
|
||||||
-- 渲染后端源文件
|
-- 渲染后端源文件
|
||||||
local render_backend = get_render_backend()
|
local render_backend = get_render_backend()
|
||||||
|
-- 图形后端工厂(始终编译)
|
||||||
|
add_files("Extra2D/src/graphics/backends/backend_factory.cpp")
|
||||||
if render_backend == "vulkan" then
|
if render_backend == "vulkan" then
|
||||||
add_files("Extra2D/src/graphics/backends/vulkan/*.cpp")
|
add_files("Extra2D/src/graphics/backends/vulkan/*.cpp")
|
||||||
add_defines("E2D_BACKEND_VULKAN")
|
add_defines("E2D_BACKEND_VULKAN")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue