refactor(render): 移除多后端支持,仅保留GLFW和OpenGL
简化渲染模块和窗口模块,移除SDL2和Vulkan后端支持,仅保留GLFW窗口后端和OpenGL渲染后端。删除相关后端工厂代码和配置文件,修改模块初始化逻辑直接使用GLFW和OpenGL实现。 - 删除SDL2和Vulkan后端相关代码 - 移除后端工厂模式和相关注册逻辑 - 修改窗口模块直接使用GLFW实现 - 修改渲染模块直接使用OpenGL实现 - 更新构建配置仅支持GLFW+OpenGL组合
This commit is contained in:
parent
8e385beeae
commit
b892736fb2
|
|
@ -1,124 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
namespace graphics {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 图形后端工厂
|
|
||||||
* 用于注册和创建图形渲染后端
|
|
||||||
*/
|
|
||||||
class BackendFactory {
|
|
||||||
public:
|
|
||||||
using BackendFn = std::function<UniquePtr<RenderBackend>()>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注册图形后端
|
|
||||||
* @param name 后端名称
|
|
||||||
* @param backend 后端创建函数
|
|
||||||
* @param windowBackends 支持的窗口后端名称列表
|
|
||||||
*/
|
|
||||||
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 创建默认渲染后端
|
|
||||||
* @return 默认渲染后端实例
|
|
||||||
*/
|
|
||||||
static UniquePtr<RenderBackend> createDefaultBackend();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 创建与指定窗口后端兼容的渲染后端
|
|
||||||
* @param windowBackend 窗口后端名称
|
|
||||||
* @return 兼容的渲染后端实例
|
|
||||||
*/
|
|
||||||
static UniquePtr<RenderBackend>
|
|
||||||
createBackendForWindow(const std::string &windowBackend);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取所有已注册的后端名称
|
|
||||||
*/
|
|
||||||
static std::vector<std::string> backends();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<std::string>
|
|
||||||
getSupportedWindowBackends(const std::string &graphicsBackend);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct BackendEntry {
|
|
||||||
BackendFn createFn;
|
|
||||||
std::vector<std::string> windowBackends;
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Vulkan 渲染器实现(占位)
|
|
||||||
*
|
|
||||||
* 这是一个占位实现,用于展示Vulkan后端应该包含的内容。
|
|
||||||
* 完整的实现需要包含Vulkan上下文、设备、交换链、管线等。
|
|
||||||
*/
|
|
||||||
class VulkanRenderer : public RenderBackend {
|
|
||||||
public:
|
|
||||||
VulkanRenderer();
|
|
||||||
~VulkanRenderer() override;
|
|
||||||
|
|
||||||
// RenderBackend 接口实现
|
|
||||||
bool init(IWindow* window) override;
|
|
||||||
void shutdown() override;
|
|
||||||
|
|
||||||
void beginFrame(const Color &clearColor) override;
|
|
||||||
void endFrame() override;
|
|
||||||
void setViewport(int x, int y, int width, int height) override;
|
|
||||||
void setVSync(bool enabled) override;
|
|
||||||
|
|
||||||
void setBlendMode(BlendMode mode) override;
|
|
||||||
void setViewProjection(const glm::mat4 &matrix) override;
|
|
||||||
|
|
||||||
void pushTransform(const glm::mat4 &transform) override;
|
|
||||||
void popTransform() override;
|
|
||||||
glm::mat4 getCurrentTransform() const override;
|
|
||||||
|
|
||||||
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels,
|
|
||||||
int channels) override;
|
|
||||||
Ptr<Texture> loadTexture(const std::string &filepath) override;
|
|
||||||
|
|
||||||
void beginSpriteBatch() override;
|
|
||||||
void drawSprite(const Texture &texture, const Rect &destRect,
|
|
||||||
const Rect &srcRect, const Color &tint, float rotation,
|
|
||||||
const Vec2 &anchor) override;
|
|
||||||
void drawSprite(const Texture &texture, const Vec2 &position,
|
|
||||||
const Color &tint) override;
|
|
||||||
void endSpriteBatch() override;
|
|
||||||
|
|
||||||
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
|
||||||
float width) override;
|
|
||||||
void drawRect(const Rect &rect, const Color &color, float width) override;
|
|
||||||
void fillRect(const Rect &rect, const Color &color) override;
|
|
||||||
void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
|
||||||
int segments, float width) override;
|
|
||||||
void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
|
||||||
int segments) override;
|
|
||||||
void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
|
||||||
const Color &color, float width) override;
|
|
||||||
void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
|
||||||
const Color &color) override;
|
|
||||||
void drawPolygon(const std::vector<Vec2> &points, const Color &color,
|
|
||||||
float width) override;
|
|
||||||
void fillPolygon(const std::vector<Vec2> &points,
|
|
||||||
const Color &color) override;
|
|
||||||
|
|
||||||
Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize,
|
|
||||||
bool useSDF = false) override;
|
|
||||||
void drawText(const FontAtlas &font, const std::string &text,
|
|
||||||
const Vec2 &position, const Color &color) override;
|
|
||||||
void drawText(const FontAtlas &font, const std::string &text, float x,
|
|
||||||
float y, const Color &color) override;
|
|
||||||
|
|
||||||
Stats getStats() const override { return stats_; }
|
|
||||||
void resetStats() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Stats stats_;
|
|
||||||
bool initialized_ = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -12,15 +12,13 @@ namespace extra2d {
|
||||||
* @brief 渲染模块配置结构
|
* @brief 渲染模块配置结构
|
||||||
*/
|
*/
|
||||||
struct RenderCfg {
|
struct RenderCfg {
|
||||||
std::string backend;
|
|
||||||
int targetFPS;
|
int targetFPS;
|
||||||
bool vsync;
|
bool vsync;
|
||||||
int multisamples;
|
int multisamples;
|
||||||
int priority;
|
int priority;
|
||||||
|
|
||||||
RenderCfg()
|
RenderCfg()
|
||||||
: backend("")
|
: targetFPS(60)
|
||||||
, targetFPS(60)
|
|
||||||
, vsync(true)
|
, vsync(true)
|
||||||
, multisamples(0)
|
, multisamples(0)
|
||||||
, priority(10)
|
, priority(10)
|
||||||
|
|
@ -29,7 +27,7 @@ struct RenderCfg {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染模块
|
* @brief 渲染模块
|
||||||
* 管理渲染后端,自动根据窗口后端选择兼容的渲染器
|
* 管理 OpenGL 渲染后端
|
||||||
*/
|
*/
|
||||||
class RenderModule : public Module {
|
class RenderModule : public Module {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
|
||||||
#include <extra2d/platform/iinput.h>
|
|
||||||
#include <extra2d/platform/iwindow.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
namespace platform {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 平台后端工厂
|
|
||||||
* 用于注册和创建平台后端
|
|
||||||
*/
|
|
||||||
class BackendFactory {
|
|
||||||
public:
|
|
||||||
using WindowFn = std::function<UniquePtr<IWindow>()>;
|
|
||||||
using InputFn = std::function<UniquePtr<IInput>()>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<IWindow> createWindow(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 创建输入实例
|
|
||||||
* @param name 后端名称
|
|
||||||
* @return 输入实例,如果后端不存在返回 nullptr
|
|
||||||
*/
|
|
||||||
static UniquePtr<IInput> createInput(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取所有已注册的后端名称
|
|
||||||
*/
|
|
||||||
static std::vector<std::string> backends();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 检查后端是否存在
|
|
||||||
*/
|
|
||||||
static bool has(const std::string &name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct BackendEntry {
|
|
||||||
WindowFn windowFn;
|
|
||||||
InputFn inputFn;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::unordered_map<std::string, BackendEntry> ®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::platform::BackendFactory::reg( \
|
|
||||||
#name, \
|
|
||||||
[]() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \
|
|
||||||
return ::extra2d::makeUnique<WinClass>(); \
|
|
||||||
}, \
|
|
||||||
[]() -> ::extra2d::UniquePtr<::extra2d::IInput> { \
|
|
||||||
return ::extra2d::makeUnique<InClass>(); \
|
|
||||||
}); \
|
|
||||||
} \
|
|
||||||
} e2d_backend_reg_##name; \
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace platform
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -16,11 +16,9 @@ struct WindowCfg {
|
||||||
int h;
|
int h;
|
||||||
bool vsync;
|
bool vsync;
|
||||||
int priority;
|
int priority;
|
||||||
std::string backend;
|
|
||||||
|
|
||||||
WindowCfg()
|
WindowCfg()
|
||||||
: title("Extra2D"), w(1280), h(720), vsync(true), priority(0),
|
: title("Extra2D"), w(1280), h(720), vsync(true), priority(0) {}
|
||||||
backend("sdl2") {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -52,12 +50,6 @@ 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_;
|
||||||
|
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/graphics/backends/backend_factory.h>
|
|
||||||
#include <extra2d/services/logger_service.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
namespace graphics {
|
|
||||||
|
|
||||||
std::unordered_map<std::string, BackendFactory::BackendEntry> &
|
|
||||||
BackendFactory::registry() {
|
|
||||||
static std::unordered_map<std::string, BackendEntry> reg;
|
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendFactory::reg(const std::string &name, BackendFn backend,
|
|
||||||
const std::vector<std::string> &windowBackends) {
|
|
||||||
registry()[name] = {backend, windowBackends};
|
|
||||||
E2D_LOG_DEBUG("已注册图形后端: {} (窗口后端数量: {})", name,
|
|
||||||
windowBackends.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<RenderBackend>
|
|
||||||
BackendFactory::createBackend(const std::string &name) {
|
|
||||||
auto ® = registry();
|
|
||||||
auto it = reg.find(name);
|
|
||||||
if (it != reg.end() && it->second.createFn) {
|
|
||||||
E2D_LOG_INFO("正在创建图形后端: {}", name);
|
|
||||||
return it->second.createFn();
|
|
||||||
}
|
|
||||||
E2D_LOG_ERROR("未找到图形后端 '{}'", name);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
|
||||||
std::string recommended = getRecommendedBackend();
|
|
||||||
if (recommended.empty()) {
|
|
||||||
E2D_LOG_ERROR("无可用的图形后端");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return createBackend(recommended);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<RenderBackend>
|
|
||||||
BackendFactory::createBackendForWindow(const std::string &windowBackend) {
|
|
||||||
std::string recommended = getRecommendedBackendForWindow(windowBackend);
|
|
||||||
if (recommended.empty()) {
|
|
||||||
E2D_LOG_ERROR("未找到与窗口后端 '{}' 兼容的图形后端", windowBackend);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return createBackend(recommended);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> BackendFactory::backends() {
|
|
||||||
std::vector<std::string> 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 ® = 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("未注册任何图形后端");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string BackendFactory::getRecommendedBackendForWindow(
|
|
||||||
const std::string &windowBackend) {
|
|
||||||
auto ® = 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("未找到与窗口后端 '{}' 兼容的图形后端", windowBackend);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BackendFactory::isCompatible(const std::string &graphicsBackend,
|
|
||||||
const std::string &windowBackend) {
|
|
||||||
auto ® = 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>
|
|
||||||
BackendFactory::getSupportedWindowBackends(const std::string &graphicsBackend) {
|
|
||||||
auto ® = registry();
|
|
||||||
auto it = reg.find(graphicsBackend);
|
|
||||||
if (it != reg.end()) {
|
|
||||||
return it->second.windowBackends;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace graphics
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
#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,150 +0,0 @@
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/graphics/backends/vulkan/vk_renderer.h>
|
|
||||||
#include <extra2d/services/logger_service.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
VulkanRenderer::VulkanRenderer() = default;
|
|
||||||
|
|
||||||
VulkanRenderer::~VulkanRenderer() { shutdown(); }
|
|
||||||
|
|
||||||
bool VulkanRenderer::init(IWindow *window) {
|
|
||||||
E2D_LOG_WARN("Vulkan 渲染器尚未完全实现");
|
|
||||||
initialized_ = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::shutdown() { initialized_ = false; }
|
|
||||||
|
|
||||||
void VulkanRenderer::beginFrame(const Color &clearColor) {
|
|
||||||
// TODO: 实现Vulkan帧开始
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::endFrame() {
|
|
||||||
// TODO: 实现Vulkan帧结束
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::setViewport(int x, int y, int width, int height) {
|
|
||||||
// TODO: 实现视口设置
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::setVSync(bool enabled) {
|
|
||||||
// TODO: 实现垂直同步设置
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::setBlendMode(BlendMode mode) {
|
|
||||||
// TODO: 实现混合模式设置
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::setViewProjection(const glm::mat4 &matrix) {
|
|
||||||
// TODO: 实现视图投影矩阵设置
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::pushTransform(const glm::mat4 &transform) {
|
|
||||||
// TODO: 实现变换矩阵入栈
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::popTransform() {
|
|
||||||
// TODO: 实现变换矩阵出栈
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 VulkanRenderer::getCurrentTransform() const {
|
|
||||||
return glm::mat4(1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr<Texture> VulkanRenderer::createTexture(int width, int height,
|
|
||||||
const uint8_t *pixels,
|
|
||||||
int channels) {
|
|
||||||
// TODO: 实现Vulkan纹理创建
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr<Texture> VulkanRenderer::loadTexture(const std::string &filepath) {
|
|
||||||
// TODO: 实现Vulkan纹理加载
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::beginSpriteBatch() {
|
|
||||||
// TODO: 实现精灵批处理开始
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawSprite(const Texture &texture, const Rect &destRect,
|
|
||||||
const Rect &srcRect, const Color &tint,
|
|
||||||
float rotation, const Vec2 &anchor) {
|
|
||||||
// TODO: 实现精灵绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawSprite(const Texture &texture, const Vec2 &position,
|
|
||||||
const Color &tint) {
|
|
||||||
// TODO: 实现简化精灵绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::endSpriteBatch() {
|
|
||||||
// TODO: 实现精灵批处理结束
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end,
|
|
||||||
const Color &color, float width) {
|
|
||||||
// TODO: 实现线条绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawRect(const Rect &rect, const Color &color,
|
|
||||||
float width) {
|
|
||||||
// TODO: 实现矩形边框绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::fillRect(const Rect &rect, const Color &color) {
|
|
||||||
// TODO: 实现矩形填充
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawCircle(const Vec2 ¢er, float radius,
|
|
||||||
const Color &color, int segments, float width) {
|
|
||||||
// TODO: 实现圆形边框绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::fillCircle(const Vec2 ¢er, float radius,
|
|
||||||
const Color &color, int segments) {
|
|
||||||
// TODO: 实现圆形填充
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2,
|
|
||||||
const Vec2 &p3, const Color &color,
|
|
||||||
float width) {
|
|
||||||
// TODO: 实现三角形边框绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2,
|
|
||||||
const Vec2 &p3, const Color &color) {
|
|
||||||
// TODO: 实现三角形填充
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawPolygon(const std::vector<Vec2> &points,
|
|
||||||
const Color &color, float width) {
|
|
||||||
// TODO: 实现多边形边框绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::fillPolygon(const std::vector<Vec2> &points,
|
|
||||||
const Color &color) {
|
|
||||||
// TODO: 实现多边形填充
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr<FontAtlas> VulkanRenderer::createFontAtlas(const std::string &filepath,
|
|
||||||
int fontSize, bool useSDF) {
|
|
||||||
// TODO: 实现字体图集创建
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text,
|
|
||||||
const Vec2 &position, const Color &color) {
|
|
||||||
// TODO: 实现文本绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text,
|
|
||||||
float x, float y, const Color &color) {
|
|
||||||
// TODO: 实现文本绘制
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::resetStats() { stats_ = Stats{}; }
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/core/registry.h>
|
#include <extra2d/core/registry.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/service_locator.h>
|
||||||
#include <extra2d/graphics/backends/backend_factory.h>
|
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
|
||||||
#include <extra2d/graphics/backends/opengl/gl_shader.h>
|
#include <extra2d/graphics/backends/opengl/gl_shader.h>
|
||||||
#include <extra2d/graphics/core/render_module.h>
|
#include <extra2d/graphics/core/render_module.h>
|
||||||
#include <extra2d/graphics/shader/shader_manager.h>
|
#include <extra2d/graphics/shader/shader_manager.h>
|
||||||
|
|
@ -10,16 +10,6 @@
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
// 前向声明后端初始化函数
|
|
||||||
namespace graphics {
|
|
||||||
#ifdef E2D_BACKEND_OPENGL
|
|
||||||
void initOpenGLBackend();
|
|
||||||
#endif
|
|
||||||
#ifdef E2D_BACKEND_VULKAN
|
|
||||||
void initVulkanBackend();
|
|
||||||
#endif
|
|
||||||
} // namespace graphics
|
|
||||||
|
|
||||||
RenderModule::RenderModule(std::function<void(RenderCfg &)> configFn) {
|
RenderModule::RenderModule(std::function<void(RenderCfg &)> configFn) {
|
||||||
configFn(cfg_);
|
configFn(cfg_);
|
||||||
}
|
}
|
||||||
|
|
@ -40,15 +30,6 @@ bool RenderModule::init() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化图形后端(注册到工厂)
|
|
||||||
#ifdef E2D_BACKEND_OPENGL
|
|
||||||
graphics::initOpenGLBackend();
|
|
||||||
#endif
|
|
||||||
#ifdef E2D_BACKEND_VULKAN
|
|
||||||
graphics::initVulkanBackend();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 使用ShaderManager的默认路径初始化
|
|
||||||
if (!ShaderManager::getInstance().isInitialized()) {
|
if (!ShaderManager::getInstance().isInitialized()) {
|
||||||
auto factory = makeShared<GLShaderFactory>();
|
auto factory = makeShared<GLShaderFactory>();
|
||||||
if (!ShaderManager::getInstance().init(factory)) {
|
if (!ShaderManager::getInstance().init(factory)) {
|
||||||
|
|
@ -56,18 +37,8 @@ bool RenderModule::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string windowBackend = winMod->getWindowBackend();
|
E2D_LOG_INFO("正在创建 OpenGL 渲染后端");
|
||||||
|
renderer_ = makeUnique<GLRenderer>();
|
||||||
if (cfg_.backend.empty()) {
|
|
||||||
E2D_LOG_INFO("未指定图形后端,正在为窗口后端自动选择:{}", windowBackend);
|
|
||||||
renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend);
|
|
||||||
} else {
|
|
||||||
if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) {
|
|
||||||
E2D_LOG_WARN("图形后端 '{}' 与窗口后端 '{}' 不兼容", cfg_.backend,
|
|
||||||
windowBackend);
|
|
||||||
}
|
|
||||||
renderer_ = graphics::BackendFactory::createBackend(cfg_.backend);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!renderer_) {
|
if (!renderer_) {
|
||||||
E2D_LOG_ERROR("创建渲染后端失败");
|
E2D_LOG_ERROR("创建渲染后端失败");
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
#include <extra2d/platform/backend_factory.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
namespace platform {
|
|
||||||
|
|
||||||
std::unordered_map<std::string, BackendFactory::BackendEntry>& BackendFactory::registry() {
|
|
||||||
static std::unordered_map<std::string, BackendEntry> reg;
|
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendFactory::reg(const std::string& name, WindowFn win, InputFn in) {
|
|
||||||
registry()[name] = {win, in};
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<IWindow> BackendFactory::createWindow(const std::string& name) {
|
|
||||||
auto& reg = registry();
|
|
||||||
auto it = reg.find(name);
|
|
||||||
if (it != reg.end() && it->second.windowFn) {
|
|
||||||
return it->second.windowFn();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<IInput> BackendFactory::createInput(const std::string& name) {
|
|
||||||
auto& reg = registry();
|
|
||||||
auto it = reg.find(name);
|
|
||||||
if (it != reg.end() && it->second.inputFn) {
|
|
||||||
return it->second.inputFn();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> BackendFactory::backends() {
|
|
||||||
std::vector<std::string> 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace platform
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#include "glfw_window.h"
|
|
||||||
#include "glfw_input.h"
|
|
||||||
#include <extra2d/platform/backend_factory.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
namespace platform {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
static bool s_glfwBackendRegistered = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initGLFWBackend() {
|
|
||||||
if (s_glfwBackendRegistered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_glfwBackendRegistered = true;
|
|
||||||
|
|
||||||
BackendFactory::reg(
|
|
||||||
"glfw",
|
|
||||||
[]() -> UniquePtr<IWindow> {
|
|
||||||
return makeUnique<GLFWWindow>();
|
|
||||||
},
|
|
||||||
[]() -> UniquePtr<IInput> {
|
|
||||||
return makeUnique<GLFWInput>();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace platform
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#include "sdl2_window.h"
|
|
||||||
#include "sdl2_input.h"
|
|
||||||
#include <extra2d/platform/backend_factory.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
namespace platform {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
static bool s_sdl2BackendRegistered = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initSDL2Backend() {
|
|
||||||
if (s_sdl2BackendRegistered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_sdl2BackendRegistered = true;
|
|
||||||
|
|
||||||
BackendFactory::reg(
|
|
||||||
"sdl2",
|
|
||||||
[]() -> UniquePtr<IWindow> {
|
|
||||||
return makeUnique<SDL2Window>();
|
|
||||||
},
|
|
||||||
[]() -> UniquePtr<IInput> {
|
|
||||||
return makeUnique<SDL2Input>();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace platform
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,454 +0,0 @@
|
||||||
#include "sdl2_input.h"
|
|
||||||
#include <cmath>
|
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/services/logger_service.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
SDL2Input::SDL2Input() {
|
|
||||||
keyCurrent_.fill(false);
|
|
||||||
keyPrevious_.fill(false);
|
|
||||||
mouseCurrent_.fill(false);
|
|
||||||
mousePrevious_.fill(false);
|
|
||||||
gamepadCurrent_.fill(false);
|
|
||||||
gamepadPrevious_.fill(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL2Input::~SDL2Input() { shutdown(); }
|
|
||||||
|
|
||||||
void SDL2Input::init() {
|
|
||||||
E2D_LOG_INFO("SDL2Input 已初始化");
|
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
|
|
||||||
E2D_LOG_WARN("初始化游戏手柄子系统失败: {}", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
openGamepad();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::shutdown() {
|
|
||||||
closeGamepad();
|
|
||||||
E2D_LOG_INFO("SDL2Input 已关闭");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::update() {
|
|
||||||
keyPrevious_ = keyCurrent_;
|
|
||||||
mousePrevious_ = mouseCurrent_;
|
|
||||||
gamepadPrevious_ = gamepadCurrent_;
|
|
||||||
|
|
||||||
scrollDelta_ = 0.0f;
|
|
||||||
mouseDelta_ = Vec2{0.0f, 0.0f};
|
|
||||||
|
|
||||||
updateGamepad();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::setEventCallback(EventCallback callback) {
|
|
||||||
eventCallback_ = std::move(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::handleSDLEvent(const SDL_Event &event) {
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_KEYDOWN: {
|
|
||||||
int key = event.key.keysym.scancode;
|
|
||||||
if (key >= 0 && key < static_cast<int>(Key::Count)) {
|
|
||||||
if (!keyCurrent_[key]) {
|
|
||||||
keyCurrent_[key] = true;
|
|
||||||
|
|
||||||
Event e = Event::createKeyPress(event.key.keysym.sym,
|
|
||||||
event.key.keysym.scancode,
|
|
||||||
event.key.keysym.mod);
|
|
||||||
dispatchEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_KEYUP: {
|
|
||||||
int key = event.key.keysym.scancode;
|
|
||||||
if (key >= 0 && key < static_cast<int>(Key::Count)) {
|
|
||||||
keyCurrent_[key] = false;
|
|
||||||
|
|
||||||
Event e = Event::createKeyRelease(event.key.keysym.sym,
|
|
||||||
event.key.keysym.scancode,
|
|
||||||
event.key.keysym.mod);
|
|
||||||
dispatchEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN: {
|
|
||||||
int btn = event.button.button - 1;
|
|
||||||
if (btn >= 0 && btn < static_cast<int>(Mouse::Count)) {
|
|
||||||
mouseCurrent_[btn] = true;
|
|
||||||
|
|
||||||
Vec2 pos{static_cast<float>(event.button.x),
|
|
||||||
static_cast<float>(event.button.y)};
|
|
||||||
Event e = Event::createMouseButtonPress(btn, 0, pos);
|
|
||||||
dispatchEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONUP: {
|
|
||||||
int btn = event.button.button - 1;
|
|
||||||
if (btn >= 0 && btn < static_cast<int>(Mouse::Count)) {
|
|
||||||
mouseCurrent_[btn] = false;
|
|
||||||
|
|
||||||
Vec2 pos{static_cast<float>(event.button.x),
|
|
||||||
static_cast<float>(event.button.y)};
|
|
||||||
Event e = Event::createMouseButtonRelease(btn, 0, pos);
|
|
||||||
dispatchEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEMOTION: {
|
|
||||||
Vec2 newPos{static_cast<float>(event.motion.x),
|
|
||||||
static_cast<float>(event.motion.y)};
|
|
||||||
Vec2 delta{static_cast<float>(event.motion.xrel),
|
|
||||||
static_cast<float>(event.motion.yrel)};
|
|
||||||
|
|
||||||
mouseDelta_ = mouseDelta_ + delta;
|
|
||||||
mousePos_ = newPos;
|
|
||||||
|
|
||||||
Event e = Event::createMouseMove(newPos, delta);
|
|
||||||
dispatchEvent(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEWHEEL: {
|
|
||||||
Vec2 offset{static_cast<float>(event.wheel.x),
|
|
||||||
static_cast<float>(event.wheel.y)};
|
|
||||||
Vec2 pos = mousePos_;
|
|
||||||
|
|
||||||
scroll_ += event.wheel.y;
|
|
||||||
scrollDelta_ += event.wheel.y;
|
|
||||||
|
|
||||||
Event e = Event::createMouseScroll(offset, pos);
|
|
||||||
dispatchEvent(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_CONTROLLERDEVICEADDED:
|
|
||||||
E2D_LOG_INFO("游戏手柄已连接: 索引 {}", event.cdevice.which);
|
|
||||||
openGamepad();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_CONTROLLERDEVICEREMOVED:
|
|
||||||
if (gamepad_ &&
|
|
||||||
event.cdevice.which ==
|
|
||||||
SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) {
|
|
||||||
E2D_LOG_INFO("游戏手柄已断开");
|
|
||||||
closeGamepad();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_CONTROLLERBUTTONDOWN:
|
|
||||||
if (gamepad_) {
|
|
||||||
int btn = event.cbutton.button;
|
|
||||||
if (btn >= 0 && btn < static_cast<int>(Gamepad::Count)) {
|
|
||||||
gamepadCurrent_[btn] = true;
|
|
||||||
|
|
||||||
GamepadButtonEvent btnEvent;
|
|
||||||
btnEvent.gamepadId = gamepadIndex_;
|
|
||||||
btnEvent.button = btn;
|
|
||||||
|
|
||||||
Event e;
|
|
||||||
e.type = EventType::GamepadButtonPressed;
|
|
||||||
e.data = btnEvent;
|
|
||||||
dispatchEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_CONTROLLERBUTTONUP:
|
|
||||||
if (gamepad_) {
|
|
||||||
int btn = event.cbutton.button;
|
|
||||||
if (btn >= 0 && btn < static_cast<int>(Gamepad::Count)) {
|
|
||||||
gamepadCurrent_[btn] = false;
|
|
||||||
|
|
||||||
GamepadButtonEvent btnEvent;
|
|
||||||
btnEvent.gamepadId = gamepadIndex_;
|
|
||||||
btnEvent.button = btn;
|
|
||||||
|
|
||||||
Event e;
|
|
||||||
e.type = EventType::GamepadButtonReleased;
|
|
||||||
e.data = btnEvent;
|
|
||||||
dispatchEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::dispatchEvent(const Event &event) {
|
|
||||||
if (eventCallback_) {
|
|
||||||
eventCallback_(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::down(Key key) const {
|
|
||||||
size_t idx = static_cast<size_t>(key);
|
|
||||||
if (idx < keyCurrent_.size()) {
|
|
||||||
return keyCurrent_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::pressed(Key key) const {
|
|
||||||
size_t idx = static_cast<size_t>(key);
|
|
||||||
if (idx < keyCurrent_.size()) {
|
|
||||||
return keyCurrent_[idx] && !keyPrevious_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::released(Key key) const {
|
|
||||||
size_t idx = static_cast<size_t>(key);
|
|
||||||
if (idx < keyCurrent_.size()) {
|
|
||||||
return !keyCurrent_[idx] && keyPrevious_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::down(Mouse btn) const {
|
|
||||||
size_t idx = static_cast<size_t>(btn);
|
|
||||||
if (idx < mouseCurrent_.size()) {
|
|
||||||
return mouseCurrent_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::pressed(Mouse btn) const {
|
|
||||||
size_t idx = static_cast<size_t>(btn);
|
|
||||||
if (idx < mouseCurrent_.size()) {
|
|
||||||
return mouseCurrent_[idx] && !mousePrevious_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::released(Mouse btn) const {
|
|
||||||
size_t idx = static_cast<size_t>(btn);
|
|
||||||
if (idx < mouseCurrent_.size()) {
|
|
||||||
return !mouseCurrent_[idx] && mousePrevious_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 SDL2Input::mouse() const { return mousePos_; }
|
|
||||||
|
|
||||||
Vec2 SDL2Input::mouseDelta() const { return mouseDelta_; }
|
|
||||||
|
|
||||||
float SDL2Input::scroll() const { return scroll_; }
|
|
||||||
|
|
||||||
float SDL2Input::scrollDelta() const { return scrollDelta_; }
|
|
||||||
|
|
||||||
void SDL2Input::setMouse(const Vec2 &pos) {
|
|
||||||
SDL_WarpMouseInWindow(nullptr, static_cast<int>(pos.x),
|
|
||||||
static_cast<int>(pos.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::gamepad() const { return gamepad_ != nullptr; }
|
|
||||||
|
|
||||||
bool SDL2Input::down(Gamepad btn) const {
|
|
||||||
size_t idx = static_cast<size_t>(btn);
|
|
||||||
if (idx < gamepadCurrent_.size()) {
|
|
||||||
return gamepadCurrent_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::pressed(Gamepad btn) const {
|
|
||||||
size_t idx = static_cast<size_t>(btn);
|
|
||||||
if (idx < gamepadCurrent_.size()) {
|
|
||||||
return gamepadCurrent_[idx] && !gamepadPrevious_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::released(Gamepad btn) const {
|
|
||||||
size_t idx = static_cast<size_t>(btn);
|
|
||||||
if (idx < gamepadCurrent_.size()) {
|
|
||||||
return !gamepadCurrent_[idx] && gamepadPrevious_[idx];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 SDL2Input::leftStick() const { return leftStick_; }
|
|
||||||
|
|
||||||
Vec2 SDL2Input::rightStick() const { return rightStick_; }
|
|
||||||
|
|
||||||
float SDL2Input::leftTrigger() const { return leftTrigger_; }
|
|
||||||
|
|
||||||
float SDL2Input::rightTrigger() const { return rightTrigger_; }
|
|
||||||
|
|
||||||
void SDL2Input::vibrate(float left, float right) {
|
|
||||||
if (gamepad_) {
|
|
||||||
Uint16 lowFreq = static_cast<Uint16>(left * 65535.0f);
|
|
||||||
Uint16 highFreq = static_cast<Uint16>(right * 65535.0f);
|
|
||||||
SDL_GameControllerRumble(gamepad_, lowFreq, highFreq, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Input::touching() const { return false; }
|
|
||||||
|
|
||||||
int SDL2Input::touchCount() const { return 0; }
|
|
||||||
|
|
||||||
Vec2 SDL2Input::touch(int index) const {
|
|
||||||
(void)index;
|
|
||||||
return Vec2{0.0f, 0.0f};
|
|
||||||
}
|
|
||||||
|
|
||||||
TouchPoint SDL2Input::touchPoint(int index) const {
|
|
||||||
(void)index;
|
|
||||||
return TouchPoint{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::updateKeyboard() {}
|
|
||||||
|
|
||||||
void SDL2Input::updateMouse() {
|
|
||||||
int x = 0, y = 0;
|
|
||||||
SDL_GetMouseState(&x, &y);
|
|
||||||
mousePos_ = Vec2{static_cast<float>(x), static_cast<float>(y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::updateGamepad() {
|
|
||||||
if (!gamepad_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto applyDeadzone = [this](float value) -> float {
|
|
||||||
if (std::abs(value) < deadzone_) {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
float sign = value >= 0.0f ? 1.0f : -1.0f;
|
|
||||||
return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_);
|
|
||||||
};
|
|
||||||
|
|
||||||
int lx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTX);
|
|
||||||
int ly = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTY);
|
|
||||||
int rx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTX);
|
|
||||||
int ry = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTY);
|
|
||||||
|
|
||||||
leftStick_.x = applyDeadzone(lx / 32767.0f);
|
|
||||||
leftStick_.y = applyDeadzone(ly / 32767.0f);
|
|
||||||
rightStick_.x = applyDeadzone(rx / 32767.0f);
|
|
||||||
rightStick_.y = applyDeadzone(ry / 32767.0f);
|
|
||||||
|
|
||||||
int lt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
|
||||||
int rt =
|
|
||||||
SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
|
||||||
|
|
||||||
leftTrigger_ = lt / 32767.0f;
|
|
||||||
rightTrigger_ = rt / 32767.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::openGamepad() {
|
|
||||||
int numJoysticks = SDL_NumJoysticks();
|
|
||||||
for (int i = 0; i < numJoysticks; ++i) {
|
|
||||||
if (SDL_IsGameController(i)) {
|
|
||||||
gamepad_ = SDL_GameControllerOpen(i);
|
|
||||||
if (gamepad_) {
|
|
||||||
gamepadIndex_ = i;
|
|
||||||
E2D_LOG_INFO("游戏手柄已打开: {}", SDL_GameControllerName(gamepad_));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Input::closeGamepad() {
|
|
||||||
if (gamepad_) {
|
|
||||||
SDL_GameControllerClose(gamepad_);
|
|
||||||
gamepad_ = nullptr;
|
|
||||||
gamepadIndex_ = -1;
|
|
||||||
gamepadCurrent_.fill(false);
|
|
||||||
gamepadPrevious_.fill(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SDL2Input::keyToSDL(Key key) { return static_cast<int>(key); }
|
|
||||||
|
|
||||||
int SDL2Input::mouseToSDL(Mouse btn) {
|
|
||||||
switch (btn) {
|
|
||||||
case Mouse::Left:
|
|
||||||
return SDL_BUTTON_LEFT;
|
|
||||||
case Mouse::Middle:
|
|
||||||
return SDL_BUTTON_MIDDLE;
|
|
||||||
case Mouse::Right:
|
|
||||||
return SDL_BUTTON_RIGHT;
|
|
||||||
case Mouse::X1:
|
|
||||||
return SDL_BUTTON_X1;
|
|
||||||
case Mouse::X2:
|
|
||||||
return SDL_BUTTON_X2;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SDL2Input::gamepadToSDL(Gamepad btn) {
|
|
||||||
switch (btn) {
|
|
||||||
case Gamepad::A:
|
|
||||||
return SDL_CONTROLLER_BUTTON_A;
|
|
||||||
case Gamepad::B:
|
|
||||||
return SDL_CONTROLLER_BUTTON_B;
|
|
||||||
case Gamepad::X:
|
|
||||||
return SDL_CONTROLLER_BUTTON_X;
|
|
||||||
case Gamepad::Y:
|
|
||||||
return SDL_CONTROLLER_BUTTON_Y;
|
|
||||||
case Gamepad::Back:
|
|
||||||
return SDL_CONTROLLER_BUTTON_BACK;
|
|
||||||
case Gamepad::Start:
|
|
||||||
return SDL_CONTROLLER_BUTTON_START;
|
|
||||||
case Gamepad::LStick:
|
|
||||||
return SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
|
||||||
case Gamepad::RStick:
|
|
||||||
return SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
|
||||||
case Gamepad::LB:
|
|
||||||
return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
|
||||||
case Gamepad::RB:
|
|
||||||
return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
|
||||||
case Gamepad::DUp:
|
|
||||||
return SDL_CONTROLLER_BUTTON_DPAD_UP;
|
|
||||||
case Gamepad::DDown:
|
|
||||||
return SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
|
||||||
case Gamepad::DLeft:
|
|
||||||
return SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
|
||||||
case Gamepad::DRight:
|
|
||||||
return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
|
|
||||||
case Gamepad::Guide:
|
|
||||||
return SDL_CONTROLLER_BUTTON_GUIDE;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Key SDL2Input::sdlToKey(int sdlKey) {
|
|
||||||
if (sdlKey >= 0 && sdlKey < static_cast<int>(Key::Count)) {
|
|
||||||
return static_cast<Key>(sdlKey);
|
|
||||||
}
|
|
||||||
return Key::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mouse SDL2Input::sdlToMouse(int sdlButton) {
|
|
||||||
switch (sdlButton) {
|
|
||||||
case SDL_BUTTON_LEFT:
|
|
||||||
return Mouse::Left;
|
|
||||||
case SDL_BUTTON_MIDDLE:
|
|
||||||
return Mouse::Middle;
|
|
||||||
case SDL_BUTTON_RIGHT:
|
|
||||||
return Mouse::Right;
|
|
||||||
case SDL_BUTTON_X1:
|
|
||||||
return Mouse::X1;
|
|
||||||
case SDL_BUTTON_X2:
|
|
||||||
return Mouse::X2;
|
|
||||||
default:
|
|
||||||
return Mouse::Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/platform/iinput.h>
|
|
||||||
#include <extra2d/event/event.h>
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SDL2 输入实现
|
|
||||||
*/
|
|
||||||
class SDL2Input : public IInput {
|
|
||||||
public:
|
|
||||||
using EventCallback = std::function<void(const Event&)>;
|
|
||||||
|
|
||||||
SDL2Input();
|
|
||||||
~SDL2Input() override;
|
|
||||||
|
|
||||||
void init() override;
|
|
||||||
void shutdown() override;
|
|
||||||
void update() override;
|
|
||||||
|
|
||||||
bool down(Key key) const override;
|
|
||||||
bool pressed(Key key) const override;
|
|
||||||
bool released(Key key) const override;
|
|
||||||
|
|
||||||
bool down(Mouse btn) const override;
|
|
||||||
bool pressed(Mouse btn) const override;
|
|
||||||
bool released(Mouse btn) const override;
|
|
||||||
Vec2 mouse() const override;
|
|
||||||
Vec2 mouseDelta() const override;
|
|
||||||
float scroll() const override;
|
|
||||||
float scrollDelta() const override;
|
|
||||||
void setMouse(const Vec2& pos) override;
|
|
||||||
|
|
||||||
bool gamepad() const override;
|
|
||||||
bool down(Gamepad btn) const override;
|
|
||||||
bool pressed(Gamepad btn) const override;
|
|
||||||
bool released(Gamepad btn) const override;
|
|
||||||
Vec2 leftStick() const override;
|
|
||||||
Vec2 rightStick() const override;
|
|
||||||
float leftTrigger() const override;
|
|
||||||
float rightTrigger() const override;
|
|
||||||
void vibrate(float left, float right) override;
|
|
||||||
|
|
||||||
bool touching() const override;
|
|
||||||
int touchCount() const override;
|
|
||||||
Vec2 touch(int index) const override;
|
|
||||||
TouchPoint touchPoint(int index) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置事件回调
|
|
||||||
* @param callback 事件回调函数
|
|
||||||
*/
|
|
||||||
void setEventCallback(EventCallback callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 处理 SDL 事件
|
|
||||||
* @param event SDL 事件
|
|
||||||
*/
|
|
||||||
void handleSDLEvent(const SDL_Event& event);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void updateKeyboard();
|
|
||||||
void updateMouse();
|
|
||||||
void updateGamepad();
|
|
||||||
void openGamepad();
|
|
||||||
void closeGamepad();
|
|
||||||
|
|
||||||
static int keyToSDL(Key key);
|
|
||||||
static int mouseToSDL(Mouse btn);
|
|
||||||
static int gamepadToSDL(Gamepad btn);
|
|
||||||
static Key sdlToKey(int sdlKey);
|
|
||||||
static Mouse sdlToMouse(int sdlButton);
|
|
||||||
|
|
||||||
void dispatchEvent(const Event& event);
|
|
||||||
|
|
||||||
std::array<bool, static_cast<size_t>(Key::Count)> keyCurrent_{};
|
|
||||||
std::array<bool, static_cast<size_t>(Key::Count)> keyPrevious_{};
|
|
||||||
|
|
||||||
std::array<bool, static_cast<size_t>(Mouse::Count)> mouseCurrent_{};
|
|
||||||
std::array<bool, static_cast<size_t>(Mouse::Count)> mousePrevious_{};
|
|
||||||
|
|
||||||
Vec2 mousePos_;
|
|
||||||
Vec2 mouseDelta_;
|
|
||||||
float scroll_ = 0.0f;
|
|
||||||
float scrollDelta_ = 0.0f;
|
|
||||||
|
|
||||||
SDL_GameController* gamepad_ = nullptr;
|
|
||||||
int gamepadIndex_ = -1;
|
|
||||||
std::array<bool, static_cast<size_t>(Gamepad::Count)> gamepadCurrent_{};
|
|
||||||
std::array<bool, static_cast<size_t>(Gamepad::Count)> gamepadPrevious_{};
|
|
||||||
Vec2 leftStick_;
|
|
||||||
Vec2 rightStick_;
|
|
||||||
float leftTrigger_ = 0.0f;
|
|
||||||
float rightTrigger_ = 0.0f;
|
|
||||||
float deadzone_ = 0.15f;
|
|
||||||
|
|
||||||
EventCallback eventCallback_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,615 +0,0 @@
|
||||||
#include "sdl2_window.h"
|
|
||||||
#include "sdl2_input.h"
|
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/event/event.h>
|
|
||||||
#include <extra2d/platform/keys.h>
|
|
||||||
#include <extra2d/services/event_service.h>
|
|
||||||
#include <extra2d/services/logger_service.h>
|
|
||||||
#include <glad/glad.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
SDL2Window::SDL2Window() {
|
|
||||||
for (int i = 0; i < 7; ++i) {
|
|
||||||
sdlCursors_[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL2Window::~SDL2Window() { destroy(); }
|
|
||||||
|
|
||||||
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 | SDL_WINDOW_RESIZABLE;
|
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
|
||||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
|
||||||
|
|
||||||
sdlWindow_ = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED,
|
|
||||||
SDL_WINDOWPOS_CENTERED, width, height, flags);
|
|
||||||
|
|
||||||
if (!sdlWindow_) {
|
|
||||||
E2D_LOG_ERROR("创建 SDL 窗口失败: {}", SDL_GetError());
|
|
||||||
deinitSDL();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
glContext_ = SDL_GL_CreateContext(sdlWindow_);
|
|
||||||
if (!glContext_) {
|
|
||||||
E2D_LOG_ERROR("创建 OpenGL 上下文失败: {}", SDL_GetError());
|
|
||||||
SDL_DestroyWindow(sdlWindow_);
|
|
||||||
sdlWindow_ = nullptr;
|
|
||||||
deinitSDL();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
|
||||||
E2D_LOG_ERROR("初始化 GLAD GLES2 失败");
|
|
||||||
SDL_GL_DeleteContext(glContext_);
|
|
||||||
glContext_ = nullptr;
|
|
||||||
SDL_DestroyWindow(sdlWindow_);
|
|
||||||
sdlWindow_ = nullptr;
|
|
||||||
deinitSDL();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
|
|
||||||
|
|
||||||
SDL_GetWindowSize(sdlWindow_, &width_, &height_);
|
|
||||||
fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
|
||||||
vsync_ = vsync;
|
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
initCursors();
|
|
||||||
#endif
|
|
||||||
updateContentScale();
|
|
||||||
|
|
||||||
input_ = makeUnique<SDL2Input>();
|
|
||||||
input_->init();
|
|
||||||
|
|
||||||
E2D_LOG_INFO("SDL2 窗口创建成功: {}x{}", width_, height_);
|
|
||||||
E2D_LOG_INFO(" 平台: OpenGL ES 3.2");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::destroy() {
|
|
||||||
if (input_) {
|
|
||||||
input_->shutdown();
|
|
||||||
input_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
deinitCursors();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (glContext_) {
|
|
||||||
SDL_GL_DeleteContext(glContext_);
|
|
||||||
glContext_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_DestroyWindow(sdlWindow_);
|
|
||||||
sdlWindow_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
deinitSDL();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::poll() {
|
|
||||||
if (!sdlWindow_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (input_) {
|
|
||||||
input_->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_PollEvent(&event)) {
|
|
||||||
handleEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::swap() {
|
|
||||||
if (sdlWindow_ && glContext_) {
|
|
||||||
SDL_GL_SwapWindow(sdlWindow_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Window::shouldClose() const { return shouldClose_; }
|
|
||||||
|
|
||||||
void SDL2Window::close() { shouldClose_ = true; }
|
|
||||||
|
|
||||||
void SDL2Window::setTitle(const std::string &title) {
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_SetWindowTitle(sdlWindow_, title.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::setSize(int w, int h) {
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_SetWindowSize(sdlWindow_, w, h);
|
|
||||||
width_ = w;
|
|
||||||
height_ = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::setPos(int x, int y) {
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_SetWindowPosition(sdlWindow_, x, y);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)x;
|
|
||||||
(void)y;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::setFullscreen(bool fs) {
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_SetWindowFullscreen(sdlWindow_, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
|
||||||
fullscreen_ = fs;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)fs;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::setVSync(bool vsync) {
|
|
||||||
if (glContext_) {
|
|
||||||
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
|
|
||||||
vsync_ = vsync;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::setVisible(bool visible) {
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
if (sdlWindow_) {
|
|
||||||
if (visible) {
|
|
||||||
SDL_ShowWindow(sdlWindow_);
|
|
||||||
} else {
|
|
||||||
SDL_HideWindow(sdlWindow_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)visible;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int SDL2Window::width() const { return width_; }
|
|
||||||
|
|
||||||
int SDL2Window::height() const { return height_; }
|
|
||||||
|
|
||||||
Size SDL2Window::size() const {
|
|
||||||
return Size(static_cast<float>(width_), static_cast<float>(height_));
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 SDL2Window::pos() const {
|
|
||||||
int x = 0, y = 0;
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_GetWindowPosition(sdlWindow_, &x, &y);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return Vec2(static_cast<float>(x), static_cast<float>(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDL2Window::fullscreen() const { return fullscreen_; }
|
|
||||||
|
|
||||||
bool SDL2Window::vsync() const { return vsync_; }
|
|
||||||
|
|
||||||
bool SDL2Window::focused() const { return focused_; }
|
|
||||||
|
|
||||||
bool SDL2Window::minimized() const { return minimized_; }
|
|
||||||
|
|
||||||
float SDL2Window::scaleX() const { return scaleX_; }
|
|
||||||
|
|
||||||
float SDL2Window::scaleY() const { return scaleY_; }
|
|
||||||
|
|
||||||
void SDL2Window::setCursor(Cursor cursor) {
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
if (cursor == Cursor::Hidden) {
|
|
||||||
SDL_ShowCursor(SDL_DISABLE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_ShowCursor(SDL_ENABLE);
|
|
||||||
|
|
||||||
int idx = static_cast<int>(cursor);
|
|
||||||
if (idx >= 0 && idx < 7 && sdlCursors_[idx]) {
|
|
||||||
SDL_SetCursor(sdlCursors_[idx]);
|
|
||||||
currentCursor_ = idx;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)cursor;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::showCursor(bool show) {
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
|
|
||||||
cursorVisible_ = show;
|
|
||||||
#else
|
|
||||||
(void)show;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::lockCursor(bool lock) {
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_SetRelativeMouseMode(lock ? SDL_TRUE : SDL_FALSE);
|
|
||||||
cursorLocked_ = lock;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)lock;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
IInput *SDL2Window::input() const { return input_.get(); }
|
|
||||||
|
|
||||||
void SDL2Window::onResize(ResizeCb cb) { resizeCb_ = cb; }
|
|
||||||
|
|
||||||
void SDL2Window::onClose(CloseCb cb) { closeCb_ = cb; }
|
|
||||||
|
|
||||||
void SDL2Window::onFocus(FocusCb cb) { focusCb_ = cb; }
|
|
||||||
|
|
||||||
void *SDL2Window::native() const { return sdlWindow_; }
|
|
||||||
|
|
||||||
bool SDL2Window::initSDL() {
|
|
||||||
static int sdlInitCount = 0;
|
|
||||||
if (sdlInitCount == 0) {
|
|
||||||
Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER;
|
|
||||||
if (SDL_Init(initFlags) != 0) {
|
|
||||||
E2D_LOG_ERROR("初始化 SDL 失败: {}", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sdlInitCount++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::deinitSDL() {
|
|
||||||
static int sdlInitCount = 1;
|
|
||||||
sdlInitCount--;
|
|
||||||
if (sdlInitCount == 0) {
|
|
||||||
SDL_Quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
|
||||||
void SDL2Window::initCursors() {
|
|
||||||
sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
|
||||||
sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
|
||||||
sdlCursors_[2] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
|
|
||||||
sdlCursors_[3] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
|
||||||
sdlCursors_[4] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
|
||||||
sdlCursors_[5] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
|
||||||
sdlCursors_[6] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::deinitCursors() {
|
|
||||||
for (int i = 0; i < 7; ++i) {
|
|
||||||
if (sdlCursors_[i]) {
|
|
||||||
SDL_FreeCursor(sdlCursors_[i]);
|
|
||||||
sdlCursors_[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void SDL2Window::updateContentScale() {
|
|
||||||
if (sdlWindow_) {
|
|
||||||
SDL_GetWindowSize(sdlWindow_, &width_, &height_);
|
|
||||||
int dw, dh;
|
|
||||||
SDL_GL_GetDrawableSize(sdlWindow_, &dw, &dh);
|
|
||||||
scaleX_ = dw > 0 ? static_cast<float>(dw) / width_ : 1.0f;
|
|
||||||
scaleY_ = dh > 0 ? static_cast<float>(dh) / height_ : 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2Window::handleEvent(const SDL_Event &event) {
|
|
||||||
if (input_) {
|
|
||||||
input_->handleSDLEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将事件推送到事件服务
|
|
||||||
auto eventService = ServiceLocator::instance().getService<IEventService>();
|
|
||||||
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_QUIT:
|
|
||||||
shouldClose_ = true;
|
|
||||||
if (closeCb_)
|
|
||||||
closeCb_();
|
|
||||||
if (eventService) {
|
|
||||||
Event e = Event::createWindowClose();
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
|
||||||
switch (event.window.event) {
|
|
||||||
case SDL_WINDOWEVENT_RESIZED:
|
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
||||||
width_ = event.window.data1;
|
|
||||||
height_ = event.window.data2;
|
|
||||||
updateContentScale();
|
|
||||||
if (resizeCb_)
|
|
||||||
resizeCb_(width_, height_);
|
|
||||||
if (eventService) {
|
|
||||||
Event e = Event::createWindowResize(width_, height_);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
|
||||||
focused_ = true;
|
|
||||||
if (focusCb_)
|
|
||||||
focusCb_(true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
|
||||||
focused_ = false;
|
|
||||||
if (focusCb_)
|
|
||||||
focusCb_(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_MINIMIZED:
|
|
||||||
minimized_ = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_RESTORED:
|
|
||||||
minimized_ = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_CLOSE:
|
|
||||||
shouldClose_ = true;
|
|
||||||
if (closeCb_)
|
|
||||||
closeCb_();
|
|
||||||
if (eventService) {
|
|
||||||
Event e = Event::createWindowClose();
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_KEYDOWN: {
|
|
||||||
if (event.key.repeat == 0 && eventService) {
|
|
||||||
// 将 SDL scancode 转换为 Key 枚举
|
|
||||||
Key key = sdlScancodeToKey(event.key.keysym.scancode);
|
|
||||||
if (key != Key::None) {
|
|
||||||
int keyCode = static_cast<int>(key);
|
|
||||||
Event e = Event::createKeyPress(keyCode, event.key.keysym.scancode,
|
|
||||||
event.key.keysym.mod);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_KEYUP: {
|
|
||||||
if (eventService) {
|
|
||||||
Key key = sdlScancodeToKey(event.key.keysym.scancode);
|
|
||||||
if (key != Key::None) {
|
|
||||||
int keyCode = static_cast<int>(key);
|
|
||||||
Event e = Event::createKeyRelease(keyCode, event.key.keysym.scancode,
|
|
||||||
event.key.keysym.mod);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN: {
|
|
||||||
if (eventService) {
|
|
||||||
Vec2 pos{static_cast<float>(event.button.x),
|
|
||||||
static_cast<float>(event.button.y)};
|
|
||||||
Event e = Event::createMouseButtonPress(event.button.button - 1, 0, pos);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONUP: {
|
|
||||||
if (eventService) {
|
|
||||||
Vec2 pos{static_cast<float>(event.button.x),
|
|
||||||
static_cast<float>(event.button.y)};
|
|
||||||
Event e =
|
|
||||||
Event::createMouseButtonRelease(event.button.button - 1, 0, pos);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEMOTION: {
|
|
||||||
if (eventService) {
|
|
||||||
Vec2 pos{static_cast<float>(event.motion.x),
|
|
||||||
static_cast<float>(event.motion.y)};
|
|
||||||
Vec2 delta{static_cast<float>(event.motion.xrel),
|
|
||||||
static_cast<float>(event.motion.yrel)};
|
|
||||||
Event e = Event::createMouseMove(pos, delta);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_MOUSEWHEEL: {
|
|
||||||
if (eventService) {
|
|
||||||
int x, y;
|
|
||||||
SDL_GetMouseState(&x, &y);
|
|
||||||
Vec2 offset{static_cast<float>(event.wheel.x),
|
|
||||||
static_cast<float>(event.wheel.y)};
|
|
||||||
Vec2 pos{static_cast<float>(x), static_cast<float>(y)};
|
|
||||||
Event e = Event::createMouseScroll(offset, pos);
|
|
||||||
eventService->pushEvent(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Key SDL2Window::sdlScancodeToKey(int scancode) {
|
|
||||||
switch (scancode) {
|
|
||||||
case SDL_SCANCODE_A:
|
|
||||||
return Key::A;
|
|
||||||
case SDL_SCANCODE_B:
|
|
||||||
return Key::B;
|
|
||||||
case SDL_SCANCODE_C:
|
|
||||||
return Key::C;
|
|
||||||
case SDL_SCANCODE_D:
|
|
||||||
return Key::D;
|
|
||||||
case SDL_SCANCODE_E:
|
|
||||||
return Key::E;
|
|
||||||
case SDL_SCANCODE_F:
|
|
||||||
return Key::F;
|
|
||||||
case SDL_SCANCODE_G:
|
|
||||||
return Key::G;
|
|
||||||
case SDL_SCANCODE_H:
|
|
||||||
return Key::H;
|
|
||||||
case SDL_SCANCODE_I:
|
|
||||||
return Key::I;
|
|
||||||
case SDL_SCANCODE_J:
|
|
||||||
return Key::J;
|
|
||||||
case SDL_SCANCODE_K:
|
|
||||||
return Key::K;
|
|
||||||
case SDL_SCANCODE_L:
|
|
||||||
return Key::L;
|
|
||||||
case SDL_SCANCODE_M:
|
|
||||||
return Key::M;
|
|
||||||
case SDL_SCANCODE_N:
|
|
||||||
return Key::N;
|
|
||||||
case SDL_SCANCODE_O:
|
|
||||||
return Key::O;
|
|
||||||
case SDL_SCANCODE_P:
|
|
||||||
return Key::P;
|
|
||||||
case SDL_SCANCODE_Q:
|
|
||||||
return Key::Q;
|
|
||||||
case SDL_SCANCODE_R:
|
|
||||||
return Key::R;
|
|
||||||
case SDL_SCANCODE_S:
|
|
||||||
return Key::S;
|
|
||||||
case SDL_SCANCODE_T:
|
|
||||||
return Key::T;
|
|
||||||
case SDL_SCANCODE_U:
|
|
||||||
return Key::U;
|
|
||||||
case SDL_SCANCODE_V:
|
|
||||||
return Key::V;
|
|
||||||
case SDL_SCANCODE_W:
|
|
||||||
return Key::W;
|
|
||||||
case SDL_SCANCODE_X:
|
|
||||||
return Key::X;
|
|
||||||
case SDL_SCANCODE_Y:
|
|
||||||
return Key::Y;
|
|
||||||
case SDL_SCANCODE_Z:
|
|
||||||
return Key::Z;
|
|
||||||
case SDL_SCANCODE_0:
|
|
||||||
return Key::Num0;
|
|
||||||
case SDL_SCANCODE_1:
|
|
||||||
return Key::Num1;
|
|
||||||
case SDL_SCANCODE_2:
|
|
||||||
return Key::Num2;
|
|
||||||
case SDL_SCANCODE_3:
|
|
||||||
return Key::Num3;
|
|
||||||
case SDL_SCANCODE_4:
|
|
||||||
return Key::Num4;
|
|
||||||
case SDL_SCANCODE_5:
|
|
||||||
return Key::Num5;
|
|
||||||
case SDL_SCANCODE_6:
|
|
||||||
return Key::Num6;
|
|
||||||
case SDL_SCANCODE_7:
|
|
||||||
return Key::Num7;
|
|
||||||
case SDL_SCANCODE_8:
|
|
||||||
return Key::Num8;
|
|
||||||
case SDL_SCANCODE_9:
|
|
||||||
return Key::Num9;
|
|
||||||
case SDL_SCANCODE_F1:
|
|
||||||
return Key::F1;
|
|
||||||
case SDL_SCANCODE_F2:
|
|
||||||
return Key::F2;
|
|
||||||
case SDL_SCANCODE_F3:
|
|
||||||
return Key::F3;
|
|
||||||
case SDL_SCANCODE_F4:
|
|
||||||
return Key::F4;
|
|
||||||
case SDL_SCANCODE_F5:
|
|
||||||
return Key::F5;
|
|
||||||
case SDL_SCANCODE_F6:
|
|
||||||
return Key::F6;
|
|
||||||
case SDL_SCANCODE_F7:
|
|
||||||
return Key::F7;
|
|
||||||
case SDL_SCANCODE_F8:
|
|
||||||
return Key::F8;
|
|
||||||
case SDL_SCANCODE_F9:
|
|
||||||
return Key::F9;
|
|
||||||
case SDL_SCANCODE_F10:
|
|
||||||
return Key::F10;
|
|
||||||
case SDL_SCANCODE_F11:
|
|
||||||
return Key::F11;
|
|
||||||
case SDL_SCANCODE_F12:
|
|
||||||
return Key::F12;
|
|
||||||
case SDL_SCANCODE_SPACE:
|
|
||||||
return Key::Space;
|
|
||||||
case SDL_SCANCODE_RETURN:
|
|
||||||
return Key::Enter;
|
|
||||||
case SDL_SCANCODE_ESCAPE:
|
|
||||||
return Key::Escape;
|
|
||||||
case SDL_SCANCODE_TAB:
|
|
||||||
return Key::Tab;
|
|
||||||
case SDL_SCANCODE_BACKSPACE:
|
|
||||||
return Key::Backspace;
|
|
||||||
case SDL_SCANCODE_INSERT:
|
|
||||||
return Key::Insert;
|
|
||||||
case SDL_SCANCODE_DELETE:
|
|
||||||
return Key::Delete;
|
|
||||||
case SDL_SCANCODE_HOME:
|
|
||||||
return Key::Home;
|
|
||||||
case SDL_SCANCODE_END:
|
|
||||||
return Key::End;
|
|
||||||
case SDL_SCANCODE_PAGEUP:
|
|
||||||
return Key::PageUp;
|
|
||||||
case SDL_SCANCODE_PAGEDOWN:
|
|
||||||
return Key::PageDown;
|
|
||||||
case SDL_SCANCODE_UP:
|
|
||||||
return Key::Up;
|
|
||||||
case SDL_SCANCODE_DOWN:
|
|
||||||
return Key::Down;
|
|
||||||
case SDL_SCANCODE_LEFT:
|
|
||||||
return Key::Left;
|
|
||||||
case SDL_SCANCODE_RIGHT:
|
|
||||||
return Key::Right;
|
|
||||||
case SDL_SCANCODE_LSHIFT:
|
|
||||||
return Key::LShift;
|
|
||||||
case SDL_SCANCODE_RSHIFT:
|
|
||||||
return Key::RShift;
|
|
||||||
case SDL_SCANCODE_LCTRL:
|
|
||||||
return Key::LCtrl;
|
|
||||||
case SDL_SCANCODE_RCTRL:
|
|
||||||
return Key::RCtrl;
|
|
||||||
case SDL_SCANCODE_LALT:
|
|
||||||
return Key::LAlt;
|
|
||||||
case SDL_SCANCODE_RALT:
|
|
||||||
return Key::RAlt;
|
|
||||||
case SDL_SCANCODE_CAPSLOCK:
|
|
||||||
return Key::CapsLock;
|
|
||||||
case SDL_SCANCODE_NUMLOCKCLEAR:
|
|
||||||
return Key::NumLock;
|
|
||||||
case SDL_SCANCODE_SCROLLLOCK:
|
|
||||||
return Key::ScrollLock;
|
|
||||||
default:
|
|
||||||
return Key::None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/platform/iwindow.h>
|
|
||||||
#include <extra2d/platform/keys.h>
|
|
||||||
#include <SDL.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
class SDL2Input;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SDL2 窗口实现
|
|
||||||
*/
|
|
||||||
class SDL2Window : public IWindow {
|
|
||||||
public:
|
|
||||||
SDL2Window();
|
|
||||||
~SDL2Window() override;
|
|
||||||
|
|
||||||
bool create(const std::string& title, int width, int height, bool vsync = true) override;
|
|
||||||
void destroy() override;
|
|
||||||
|
|
||||||
void poll() override;
|
|
||||||
void swap() override;
|
|
||||||
bool shouldClose() const override;
|
|
||||||
void close() override;
|
|
||||||
|
|
||||||
void setTitle(const std::string& title) override;
|
|
||||||
void setSize(int w, int h) override;
|
|
||||||
void setPos(int x, int y) override;
|
|
||||||
void setFullscreen(bool fs) override;
|
|
||||||
void setVSync(bool vsync) override;
|
|
||||||
void setVisible(bool visible) override;
|
|
||||||
|
|
||||||
int width() const override;
|
|
||||||
int height() const override;
|
|
||||||
Size size() const override;
|
|
||||||
Vec2 pos() const override;
|
|
||||||
bool fullscreen() const override;
|
|
||||||
bool vsync() const override;
|
|
||||||
bool focused() const override;
|
|
||||||
bool minimized() const override;
|
|
||||||
|
|
||||||
float scaleX() const override;
|
|
||||||
float scaleY() const override;
|
|
||||||
|
|
||||||
void setCursor(Cursor cursor) override;
|
|
||||||
void showCursor(bool show) override;
|
|
||||||
void lockCursor(bool lock) override;
|
|
||||||
|
|
||||||
IInput* input() const override;
|
|
||||||
|
|
||||||
void onResize(ResizeCb cb) override;
|
|
||||||
void onClose(CloseCb cb) override;
|
|
||||||
void onFocus(FocusCb cb) override;
|
|
||||||
|
|
||||||
void* native() const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取 SDL 窗口句柄
|
|
||||||
*/
|
|
||||||
SDL_Window* sdlWindow() const { return sdlWindow_; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取 OpenGL 上下文
|
|
||||||
*/
|
|
||||||
SDL_GLContext glContext() const { return glContext_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool initSDL();
|
|
||||||
void deinitSDL();
|
|
||||||
void initCursors();
|
|
||||||
void deinitCursors();
|
|
||||||
void updateContentScale();
|
|
||||||
void handleEvent(const SDL_Event& event);
|
|
||||||
Key sdlScancodeToKey(int scancode);
|
|
||||||
|
|
||||||
SDL_Window* sdlWindow_ = nullptr;
|
|
||||||
SDL_GLContext glContext_ = nullptr;
|
|
||||||
SDL_Cursor* sdlCursors_[7] = {};
|
|
||||||
int currentCursor_ = 0;
|
|
||||||
|
|
||||||
UniquePtr<SDL2Input> input_;
|
|
||||||
|
|
||||||
int width_ = 1280;
|
|
||||||
int height_ = 720;
|
|
||||||
bool fullscreen_ = false;
|
|
||||||
bool vsync_ = true;
|
|
||||||
bool focused_ = true;
|
|
||||||
bool minimized_ = false;
|
|
||||||
bool shouldClose_ = false;
|
|
||||||
float scaleX_ = 1.0f;
|
|
||||||
float scaleY_ = 1.0f;
|
|
||||||
bool cursorVisible_ = true;
|
|
||||||
bool cursorLocked_ = false;
|
|
||||||
|
|
||||||
ResizeCb resizeCb_;
|
|
||||||
CloseCb closeCb_;
|
|
||||||
FocusCb focusCb_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,23 +1,15 @@
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/service_locator.h>
|
||||||
#include <extra2d/platform/backend_factory.h>
|
|
||||||
#include <extra2d/platform/window_module.h>
|
#include <extra2d/platform/window_module.h>
|
||||||
#include <extra2d/services/logger_service.h>
|
#include <extra2d/services/logger_service.h>
|
||||||
|
|
||||||
|
#include "backends/glfw/glfw_window.h"
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
// 前向声明后端初始化函数
|
|
||||||
namespace platform {
|
|
||||||
#if defined(E2D_BACKEND_SDL2)
|
|
||||||
void initSDL2Backend();
|
|
||||||
#elif defined(E2D_BACKEND_GLFW)
|
|
||||||
void initGLFWBackend();
|
|
||||||
#endif
|
|
||||||
} // namespace platform
|
|
||||||
|
|
||||||
WindowModule::WindowModule(std::function<void(WindowCfg &)> configFn) {
|
WindowModule::WindowModule(std::function<void(WindowCfg &)> configFn) {
|
||||||
configFn(cfg_);
|
configFn(cfg_);
|
||||||
}
|
}
|
||||||
|
|
@ -32,23 +24,11 @@ bool WindowModule::init() {
|
||||||
if (initialized_)
|
if (initialized_)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// 初始化后端(注册到工厂)
|
E2D_LOG_INFO("正在创建 GLFW 窗口,尺寸 {}x{}", cfg_.w, cfg_.h);
|
||||||
#if defined(E2D_BACKEND_SDL2)
|
|
||||||
platform::initSDL2Backend();
|
|
||||||
#elif defined(E2D_BACKEND_GLFW)
|
|
||||||
platform::initGLFWBackend();
|
|
||||||
#else
|
|
||||||
#error "No window backend defined"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
E2D_LOG_INFO("窗口后端已初始化");
|
win_ = makeUnique<GLFWWindow>();
|
||||||
|
|
||||||
E2D_LOG_INFO("正在创建窗口,尺寸 {}x{}", cfg_.w, cfg_.h);
|
|
||||||
|
|
||||||
// 创建窗口(使用配置的后端)
|
|
||||||
win_ = platform::BackendFactory::createWindow(cfg_.backend);
|
|
||||||
if (!win_) {
|
if (!win_) {
|
||||||
E2D_LOG_ERROR("创建窗口后端失败: {}", cfg_.backend);
|
E2D_LOG_ERROR("创建窗口失败");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
125
xmake.lua
125
xmake.lua
|
|
@ -8,7 +8,8 @@
|
||||||
-- - macOS
|
-- - macOS
|
||||||
-- - Nintendo Switch
|
-- - Nintendo Switch
|
||||||
--
|
--
|
||||||
-- 窗口后端: SDL2 / GLFW
|
-- 窗口后端: GLFW
|
||||||
|
-- 渲染后端: OpenGL
|
||||||
-- ==============================================
|
-- ==============================================
|
||||||
|
|
||||||
-- 项目元信息
|
-- 项目元信息
|
||||||
|
|
@ -33,20 +34,6 @@ option("debug_logs")
|
||||||
set_description("Enable debug logging")
|
set_description("Enable debug logging")
|
||||||
option_end()
|
option_end()
|
||||||
|
|
||||||
option("window_backend")
|
|
||||||
set_default("sdl2")
|
|
||||||
set_showmenu(true)
|
|
||||||
set_description("Window backend: sdl2 or glfw")
|
|
||||||
set_values("sdl2", "glfw")
|
|
||||||
option_end()
|
|
||||||
|
|
||||||
option("render_backend")
|
|
||||||
set_default("opengl")
|
|
||||||
set_showmenu(true)
|
|
||||||
set_description("Render backend: opengl or vulkan")
|
|
||||||
set_values("opengl", "vulkan")
|
|
||||||
option_end()
|
|
||||||
|
|
||||||
-- ==============================================
|
-- ==============================================
|
||||||
-- 平台检测与配置
|
-- 平台检测与配置
|
||||||
-- ==============================================
|
-- ==============================================
|
||||||
|
|
@ -99,25 +86,7 @@ end
|
||||||
if target_plat ~= "switch" then
|
if target_plat ~= "switch" then
|
||||||
add_requires("glm")
|
add_requires("glm")
|
||||||
add_requires("nlohmann_json")
|
add_requires("nlohmann_json")
|
||||||
|
add_requires("glfw")
|
||||||
-- 窗口后端依赖
|
|
||||||
local backend = get_config("window_backend") or "sdl2"
|
|
||||||
if backend == "glfw" then
|
|
||||||
add_requires("glfw")
|
|
||||||
else
|
|
||||||
local sdl2_configs = {
|
|
||||||
configs = {
|
|
||||||
wayland = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if target_plat == "linux" then
|
|
||||||
local is_wayland = os.getenv("XDG_SESSION_TYPE") == "wayland"
|
|
||||||
if is_wayland then
|
|
||||||
sdl2_configs.configs.wayland = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
add_requires("libsdl2", sdl2_configs)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -171,30 +140,14 @@ target("demo_basic")
|
||||||
|
|
||||||
-- 平台配置
|
-- 平台配置
|
||||||
local plat = get_config("plat") or os.host()
|
local plat = get_config("plat") or os.host()
|
||||||
local backend = get_config("window_backend") or "sdl2"
|
|
||||||
if plat == "mingw" or plat == "windows" then
|
if plat == "mingw" or plat == "windows" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
||||||
elseif plat == "linux" then
|
elseif plat == "linux" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("GL", "dl", "pthread")
|
add_syslinks("GL", "dl", "pthread")
|
||||||
elseif plat == "macosx" then
|
elseif plat == "macosx" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -212,30 +165,14 @@ target("demo_text_rendering")
|
||||||
|
|
||||||
-- 平台配置
|
-- 平台配置
|
||||||
local plat = get_config("plat") or os.host()
|
local plat = get_config("plat") or os.host()
|
||||||
local backend = get_config("window_backend") or "sdl2"
|
|
||||||
if plat == "mingw" or plat == "windows" then
|
if plat == "mingw" or plat == "windows" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
||||||
elseif plat == "linux" then
|
elseif plat == "linux" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("GL", "dl", "pthread")
|
add_syslinks("GL", "dl", "pthread")
|
||||||
elseif plat == "macosx" then
|
elseif plat == "macosx" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -272,30 +209,14 @@ target("demo_hello_module")
|
||||||
|
|
||||||
-- 平台配置
|
-- 平台配置
|
||||||
local plat = get_config("plat") or os.host()
|
local plat = get_config("plat") or os.host()
|
||||||
local backend = get_config("window_backend") or "sdl2"
|
|
||||||
if plat == "mingw" or plat == "windows" then
|
if plat == "mingw" or plat == "windows" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
||||||
elseif plat == "linux" then
|
elseif plat == "linux" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("GL", "dl", "pthread")
|
add_syslinks("GL", "dl", "pthread")
|
||||||
elseif plat == "macosx" then
|
elseif plat == "macosx" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -313,30 +234,14 @@ target("demo_image_display")
|
||||||
|
|
||||||
-- 平台配置
|
-- 平台配置
|
||||||
local plat = get_config("plat") or os.host()
|
local plat = get_config("plat") or os.host()
|
||||||
local backend = get_config("window_backend") or "sdl2"
|
|
||||||
if plat == "mingw" or plat == "windows" then
|
if plat == "mingw" or plat == "windows" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi")
|
||||||
elseif plat == "linux" then
|
elseif plat == "linux" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_syslinks("GL", "dl", "pthread")
|
add_syslinks("GL", "dl", "pthread")
|
||||||
elseif plat == "macosx" then
|
elseif plat == "macosx" then
|
||||||
add_packages("glm", "nlohmann_json")
|
add_packages("glm", "nlohmann_json", "glfw")
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw")
|
|
||||||
else
|
|
||||||
add_packages("libsdl2")
|
|
||||||
end
|
|
||||||
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,8 @@
|
||||||
-- Extra2D 引擎库共享配置
|
-- Extra2D 引擎库共享配置
|
||||||
-- 被主项目和示例共享使用
|
-- 被主项目和示例共享使用
|
||||||
--
|
--
|
||||||
-- 窗口后端支持 SDL2 和 GLFW:
|
-- 窗口后端: GLFW
|
||||||
-- - Windows (MinGW) - 支持 SDL2 和 GLFW
|
-- 渲染后端: OpenGL
|
||||||
-- - Linux - 支持 SDL2 和 GLFW
|
|
||||||
-- - macOS - 支持 SDL2 和 GLFW
|
|
||||||
-- - Nintendo Switch - 使用系统提供的后端
|
|
||||||
-- ==============================================
|
-- ==============================================
|
||||||
|
|
||||||
-- 获取当前平台
|
-- 获取当前平台
|
||||||
|
|
@ -14,16 +11,6 @@ local function get_current_plat()
|
||||||
return get_config("plat") or os.host()
|
return get_config("plat") or os.host()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 获取窗口后端
|
|
||||||
local function get_window_backend()
|
|
||||||
return get_config("window_backend") or "sdl2"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 获取渲染后端
|
|
||||||
local function get_render_backend()
|
|
||||||
return get_config("render_backend") or "opengl"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 定义 Extra2D 引擎库目标
|
-- 定义 Extra2D 引擎库目标
|
||||||
function define_extra2d_engine()
|
function define_extra2d_engine()
|
||||||
target("extra2d")
|
target("extra2d")
|
||||||
|
|
@ -32,28 +19,12 @@ function define_extra2d_engine()
|
||||||
-- 引擎核心源文件(后端无关)
|
-- 引擎核心源文件(后端无关)
|
||||||
add_files("Extra2D/src/**.cpp|platform/backends/**.cpp|graphics/backends/**.cpp")
|
add_files("Extra2D/src/**.cpp|platform/backends/**.cpp|graphics/backends/**.cpp")
|
||||||
|
|
||||||
-- 渲染后端源文件
|
-- OpenGL 渲染后端源文件
|
||||||
local render_backend = get_render_backend()
|
add_files("Extra2D/src/graphics/backends/opengl/*.cpp")
|
||||||
-- 图形后端工厂(始终编译)
|
add_files("Extra2D/src/glad/glad.c")
|
||||||
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")
|
|
||||||
else
|
|
||||||
add_files("Extra2D/src/graphics/backends/opengl/*.cpp")
|
|
||||||
add_files("Extra2D/src/glad/glad.c")
|
|
||||||
add_defines("E2D_BACKEND_OPENGL")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 窗口后端源文件
|
-- GLFW 窗口后端源文件
|
||||||
local backend = get_window_backend()
|
add_files("Extra2D/src/platform/backends/glfw/*.cpp")
|
||||||
if backend == "glfw" then
|
|
||||||
add_files("Extra2D/src/platform/backends/glfw/*.cpp")
|
|
||||||
add_defines("E2D_BACKEND_GLFW")
|
|
||||||
else
|
|
||||||
add_files("Extra2D/src/platform/backends/sdl2/*.cpp")
|
|
||||||
add_defines("E2D_BACKEND_SDL2")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 头文件路径
|
-- 头文件路径
|
||||||
add_includedirs("Extra2D/include", {public = true})
|
add_includedirs("Extra2D/include", {public = true})
|
||||||
|
|
@ -68,47 +39,21 @@ function define_extra2d_engine()
|
||||||
add_includedirs(devkitPro .. "/portlibs/switch/include", {public = true})
|
add_includedirs(devkitPro .. "/portlibs/switch/include", {public = true})
|
||||||
add_linkdirs(devkitPro .. "/portlibs/switch/lib")
|
add_linkdirs(devkitPro .. "/portlibs/switch/lib")
|
||||||
|
|
||||||
-- Switch 平台根据后端选择链接库
|
-- GLFW 后端
|
||||||
local backend = get_window_backend()
|
add_syslinks("glfw", "GLESv2", "EGL", "glapi", "drm_nouveau", "nx", "m",
|
||||||
if backend == "glfw" then
|
{public = true})
|
||||||
-- GLFW 后端(使用 libnx 提供的 GLFW)
|
|
||||||
add_syslinks("glfw", "GLESv2", "EGL", "glapi", "drm_nouveau", "nx", "m",
|
|
||||||
{public = true})
|
|
||||||
else
|
|
||||||
-- SDL2 后端
|
|
||||||
add_syslinks("SDL2", "GLESv2", "EGL", "glapi", "drm_nouveau", "nx", "m",
|
|
||||||
{public = true})
|
|
||||||
end
|
|
||||||
elseif plat == "mingw" or plat == "windows" then
|
elseif plat == "mingw" or plat == "windows" then
|
||||||
-- Windows (MinGW) 平台配置
|
-- Windows (MinGW) 平台配置
|
||||||
add_packages("glm", "nlohmann_json", {public = true})
|
add_packages("glm", "nlohmann_json", "glfw", {public = true})
|
||||||
local backend = get_window_backend()
|
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw", {public = true})
|
|
||||||
else
|
|
||||||
add_packages("libsdl2", {public = true})
|
|
||||||
end
|
|
||||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi",
|
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi",
|
||||||
{public = true})
|
{public = true})
|
||||||
elseif plat == "linux" then
|
elseif plat == "linux" then
|
||||||
-- Linux 平台配置
|
-- Linux 平台配置
|
||||||
add_packages("glm", "nlohmann_json", {public = true})
|
add_packages("glm", "nlohmann_json", "glfw", {public = true})
|
||||||
local backend = get_window_backend()
|
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw", {public = true})
|
|
||||||
else
|
|
||||||
add_packages("libsdl2", {public = true})
|
|
||||||
end
|
|
||||||
add_syslinks("GL", "dl", "pthread", {public = true})
|
add_syslinks("GL", "dl", "pthread", {public = true})
|
||||||
elseif plat == "macosx" then
|
elseif plat == "macosx" then
|
||||||
-- macOS 平台配置
|
-- macOS 平台配置
|
||||||
add_packages("glm", "nlohmann_json", {public = true})
|
add_packages("glm", "nlohmann_json", "glfw", {public = true})
|
||||||
local backend = get_window_backend()
|
|
||||||
if backend == "glfw" then
|
|
||||||
add_packages("glfw", {public = true})
|
|
||||||
else
|
|
||||||
add_packages("libsdl2", {public = true})
|
|
||||||
end
|
|
||||||
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo", {public = true})
|
add_frameworks("OpenGL", "Cocoa", "IOKit", "CoreVideo", {public = true})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue