feat(switch): 添加 Nintendo Switch 平台支持
- 添加 Switch 平台专用的日志输出和初始化处理 - 修改窗口模块以支持 OpenGL ES 3.2 渲染 - 更新构建系统以支持 Switch 平台编译 - 添加 Switch 平台文件系统操作支持 - 移除 Vulkan 相关依赖,改用 OpenGL ES - 更新插件加载器以适配 Switch 平台限制
This commit is contained in:
parent
fb11f2a71e
commit
6717015e28
|
|
@ -20,9 +20,9 @@ using ResizeCb = std::function<void(int32 w, int32 h)>;
|
||||||
using CloseCb = std::function<void()>;
|
using CloseCb = std::function<void()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 窗口模块 - Vulkan 版本
|
* @brief 窗口模块 - OpenGL ES 3.2 版本
|
||||||
*
|
*
|
||||||
* 管理 SDL2 窗口,支持 Vulkan 渲染
|
* 管理 SDL2 窗口,支持 OpenGL ES 3.2 渲染
|
||||||
* 使用新的 Module 基类,支持自动注册
|
* 使用新的 Module 基类,支持自动注册
|
||||||
*/
|
*/
|
||||||
class WindowModule : public Module {
|
class WindowModule : public Module {
|
||||||
|
|
@ -122,18 +122,26 @@ public:
|
||||||
bool shouldClose() const { return shouldClose_; }
|
bool shouldClose() const { return shouldClose_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取 Vulkan 所需的窗口扩展
|
* @brief 创建 OpenGL ES 上下文
|
||||||
* @return 扩展名称列表
|
|
||||||
*/
|
|
||||||
std::vector<const char *> getVulkanExtensions() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 创建 Vulkan 表面
|
|
||||||
* @param instance Vulkan 实例
|
|
||||||
* @param surface 输出的表面句柄
|
|
||||||
* @return 是否成功
|
* @return 是否成功
|
||||||
*/
|
*/
|
||||||
bool createVulkanSurface(void *instance, void **surface) const;
|
bool createGLContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 销毁 OpenGL ES 上下文
|
||||||
|
*/
|
||||||
|
void destroyGLContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 交换缓冲区(呈现渲染结果)
|
||||||
|
*/
|
||||||
|
void swapBuffers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取 OpenGL ES 上下文句柄
|
||||||
|
* @return SDL_GLContext 句柄
|
||||||
|
*/
|
||||||
|
void* getGLContext() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleWindowEvent(const SDL_WindowEvent &evt);
|
void handleWindowEvent(const SDL_WindowEvent &evt);
|
||||||
|
|
@ -147,6 +155,7 @@ private:
|
||||||
void onModuleConfig(const AppConfig &config);
|
void onModuleConfig(const AppConfig &config);
|
||||||
|
|
||||||
SDL_Window *window_ = nullptr;
|
SDL_Window *window_ = nullptr;
|
||||||
|
SDL_GLContext glContext_ = nullptr;
|
||||||
bool shouldClose_ = false;
|
bool shouldClose_ = false;
|
||||||
|
|
||||||
CloseCb onClose_;
|
CloseCb onClose_;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,11 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <types/base/types.h>
|
#include <types/base/types.h>
|
||||||
|
|
||||||
|
// Switch 平台支持
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
#include <switch.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TEST_BUILD
|
#ifndef TEST_BUILD
|
||||||
// SDL2 日志头文件(测试构建时不使用)
|
// SDL2 日志头文件(测试构建时不使用)
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define mkdir_impl(path, mode) _mkdir(path)
|
#define mkdir_impl(path, mode) _mkdir(path)
|
||||||
|
#elif defined(__SWITCH__)
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
// Switch 使用 ::mkdir 避免与类成员函数冲突
|
||||||
|
#define mkdir_impl(path, mode) ::mkdir(path, mode)
|
||||||
#else
|
#else
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,38 @@
|
||||||
#include <platform/window_module.h>
|
|
||||||
#include <config/app_config.h>
|
#include <config/app_config.h>
|
||||||
#include <event/events.h>
|
#include <event/events.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <platform/window_module.h>
|
||||||
#include <utils/logger.h>
|
#include <utils/logger.h>
|
||||||
|
|
||||||
// SDL Vulkan support
|
// OpenGL ES 3.2 with GLAD
|
||||||
#include <SDL_vulkan.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
// Vulkan
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
WindowModule::WindowModule() = default;
|
WindowModule::WindowModule() = default;
|
||||||
|
|
||||||
WindowModule::~WindowModule() {
|
WindowModule::~WindowModule() { shutdown(); }
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowModule::WindowModule(WindowModule &&other) noexcept
|
WindowModule::WindowModule(WindowModule &&other) noexcept
|
||||||
: window_(other.window_)
|
: window_(other.window_), glContext_(other.glContext_),
|
||||||
, shouldClose_(other.shouldClose_)
|
shouldClose_(other.shouldClose_), onClose_(std::move(other.onClose_)),
|
||||||
, onClose_(std::move(other.onClose_))
|
onResize_(std::move(other.onResize_)),
|
||||||
, onResize_(std::move(other.onResize_))
|
configListener_(std::move(other.configListener_)) {
|
||||||
, configListener_(std::move(other.configListener_)) {
|
|
||||||
other.window_ = nullptr;
|
other.window_ = nullptr;
|
||||||
|
other.glContext_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowModule &WindowModule::operator=(WindowModule &&other) noexcept {
|
WindowModule &WindowModule::operator=(WindowModule &&other) noexcept {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
shutdown();
|
shutdown();
|
||||||
window_ = other.window_;
|
window_ = other.window_;
|
||||||
|
glContext_ = other.glContext_;
|
||||||
shouldClose_ = other.shouldClose_;
|
shouldClose_ = other.shouldClose_;
|
||||||
onClose_ = std::move(other.onClose_);
|
onClose_ = std::move(other.onClose_);
|
||||||
onResize_ = std::move(other.onResize_);
|
onResize_ = std::move(other.onResize_);
|
||||||
configListener_ = std::move(other.configListener_);
|
configListener_ = std::move(other.configListener_);
|
||||||
other.window_ = nullptr;
|
other.window_ = nullptr;
|
||||||
|
other.glContext_ = nullptr;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -47,15 +44,16 @@ bool WindowModule::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听模块配置事件
|
// 监听模块配置事件
|
||||||
configListener_ = std::make_unique<events::OnModuleConfig<AppConfig>::Listener>();
|
configListener_ =
|
||||||
configListener_->bind([this](const AppConfig& config) {
|
std::make_unique<events::OnModuleConfig<AppConfig>::Listener>();
|
||||||
this->onModuleConfig(config);
|
configListener_->bind(
|
||||||
});
|
[this](const AppConfig &config) { this->onModuleConfig(config); });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowModule::shutdown() {
|
void WindowModule::shutdown() {
|
||||||
|
destroyGLContext();
|
||||||
if (window_) {
|
if (window_) {
|
||||||
SDL_DestroyWindow(window_);
|
SDL_DestroyWindow(window_);
|
||||||
window_ = nullptr;
|
window_ = nullptr;
|
||||||
|
|
@ -66,7 +64,7 @@ bool WindowModule::create(const WindowCfg& cfg) {
|
||||||
if (window_)
|
if (window_)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN;
|
uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
|
||||||
if (cfg.resizable) {
|
if (cfg.resizable) {
|
||||||
flags |= SDL_WINDOW_RESIZABLE;
|
flags |= SDL_WINDOW_RESIZABLE;
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +72,8 @@ bool WindowModule::create(const WindowCfg& cfg) {
|
||||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
window_ = SDL_CreateWindow(cfg.title.c_str(), SDL_WINDOWPOS_CENTERED,
|
window_ =
|
||||||
|
SDL_CreateWindow(cfg.title.c_str(), SDL_WINDOWPOS_CENTERED,
|
||||||
SDL_WINDOWPOS_CENTERED, cfg.width, cfg.height, flags);
|
SDL_WINDOWPOS_CENTERED, cfg.width, cfg.height, flags);
|
||||||
|
|
||||||
if (!window_) {
|
if (!window_) {
|
||||||
|
|
@ -108,6 +107,12 @@ bool WindowModule::pollEvents() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
// Switch 平台:每帧更新控制台,确保日志实时显示
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
return !shouldClose_;
|
return !shouldClose_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,25 +227,52 @@ bool WindowModule::isVisible() const {
|
||||||
return (flags & SDL_WINDOW_SHOWN) != 0;
|
return (flags & SDL_WINDOW_SHOWN) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> WindowModule::getVulkanExtensions() const {
|
bool WindowModule::createGLContext() {
|
||||||
std::vector<const char*> extensions;
|
|
||||||
if (!window_) {
|
if (!window_) {
|
||||||
return extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 count = 0;
|
|
||||||
SDL_Vulkan_GetInstanceExtensions(window_, &count, nullptr);
|
|
||||||
extensions.resize(count);
|
|
||||||
SDL_Vulkan_GetInstanceExtensions(window_, &count, extensions.data());
|
|
||||||
|
|
||||||
return extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowModule::createVulkanSurface(void* instance, void** surface) const {
|
|
||||||
if (!window_ || !instance || !surface) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return SDL_Vulkan_CreateSurface(window_, static_cast<VkInstance>(instance), reinterpret_cast<VkSurfaceKHR*>(surface));
|
|
||||||
|
// 创建 OpenGL ES 3.2 上下文
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||||
|
|
||||||
|
glContext_ = SDL_GL_CreateContext(window_);
|
||||||
|
if (!glContext_) {
|
||||||
|
E2D_LOG_ERROR("Failed to create OpenGL ES context: {}", SDL_GetError());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化 GLAD
|
||||||
|
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||||
|
E2D_LOG_ERROR("Failed to initialize GLAD");
|
||||||
|
SDL_GL_DeleteContext(glContext_);
|
||||||
|
glContext_ = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
E2D_LOG_INFO("OpenGL ES context created: {}.{}", GLVersion.major,
|
||||||
|
GLVersion.minor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowModule::destroyGLContext() {
|
||||||
|
if (glContext_) {
|
||||||
|
SDL_GL_DeleteContext(glContext_);
|
||||||
|
glContext_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowModule::swapBuffers() {
|
||||||
|
if (window_) {
|
||||||
|
SDL_GL_SwapWindow(window_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *WindowModule::getGLContext() const { return glContext_; }
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
#include <plugin/plugin_loader.h>
|
|
||||||
#include <event/event_bus.h>
|
#include <event/event_bus.h>
|
||||||
#include <algorithm>
|
#include <plugin/plugin_loader.h>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#elif defined(__SWITCH__)
|
||||||
|
// Nintendo Switch 平台使用 libnx,不支持传统动态库加载
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -48,9 +49,8 @@ bool PluginLoader::loadFromLibrary(const char* path) {
|
||||||
|
|
||||||
// 获取创建函数
|
// 获取创建函数
|
||||||
using CreateFunc = IPlugin *(*)();
|
using CreateFunc = IPlugin *(*)();
|
||||||
CreateFunc createFunc = reinterpret_cast<CreateFunc>(
|
CreateFunc createFunc =
|
||||||
getSymbol(handle, "extra2d_create_plugin")
|
reinterpret_cast<CreateFunc>(getSymbol(handle, "extra2d_create_plugin"));
|
||||||
);
|
|
||||||
|
|
||||||
if (!createFunc) {
|
if (!createFunc) {
|
||||||
unloadDynamicLibrary(handle);
|
unloadDynamicLibrary(handle);
|
||||||
|
|
@ -83,7 +83,8 @@ bool PluginLoader::loadFromLibrary(const char* path) {
|
||||||
sortedPlugins_.clear();
|
sortedPlugins_.clear();
|
||||||
|
|
||||||
// 插件加载事件(暂不发送,避免依赖 events.h)
|
// 插件加载事件(暂不发送,避免依赖 events.h)
|
||||||
// event::broadcast<events::OnPluginLoaded>(name, plugin->getInfo().version.c_str());
|
// event::broadcast<events::OnPluginLoaded>(name,
|
||||||
|
// plugin->getInfo().version.c_str());
|
||||||
|
|
||||||
// 如果已经初始化,立即加载插件
|
// 如果已经初始化,立即加载插件
|
||||||
if (inited_) {
|
if (inited_) {
|
||||||
|
|
@ -121,7 +122,8 @@ void PluginLoader::registerPlugin(IPlugin* plugin) {
|
||||||
sortedPlugins_.clear();
|
sortedPlugins_.clear();
|
||||||
|
|
||||||
// 插件加载事件(暂不发送,避免依赖 events.h)
|
// 插件加载事件(暂不发送,避免依赖 events.h)
|
||||||
// event::broadcast<events::OnPluginLoaded>(name, plugin->getInfo().version.c_str());
|
// event::broadcast<events::OnPluginLoaded>(name,
|
||||||
|
// plugin->getInfo().version.c_str());
|
||||||
|
|
||||||
// 如果已经初始化,立即加载插件
|
// 如果已经初始化,立即加载插件
|
||||||
if (inited_) {
|
if (inited_) {
|
||||||
|
|
@ -193,7 +195,8 @@ bool PluginLoader::initAll() {
|
||||||
|
|
||||||
// 检查所有插件的依赖是否满足
|
// 检查所有插件的依赖是否满足
|
||||||
for (const auto &pair : plugins_) {
|
for (const auto &pair : plugins_) {
|
||||||
if (pair.second.plugin && !checkDependencies(pair.second.plugin->getDependencies())) {
|
if (pair.second.plugin &&
|
||||||
|
!checkDependencies(pair.second.plugin->getDependencies())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -229,9 +232,7 @@ void PluginLoader::shutdownAll() {
|
||||||
inited_ = false;
|
inited_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PluginLoader::getPluginCount() const {
|
size_t PluginLoader::getPluginCount() const { return plugins_.size(); }
|
||||||
return plugins_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginLoader::addSearchPath(const char *path) {
|
void PluginLoader::addSearchPath(const char *path) {
|
||||||
if (path) {
|
if (path) {
|
||||||
|
|
@ -253,7 +254,8 @@ bool PluginLoader::resolveDependencies(IPlugin* plugin) {
|
||||||
return checkDependencies(plugin->getDependencies());
|
return checkDependencies(plugin->getDependencies());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PluginLoader::checkDependencies(const std::vector<std::string>& dependencies) {
|
bool PluginLoader::checkDependencies(
|
||||||
|
const std::vector<std::string> &dependencies) {
|
||||||
for (const auto &dep : dependencies) {
|
for (const auto &dep : dependencies) {
|
||||||
if (!hasPlugin(dep.c_str())) {
|
if (!hasPlugin(dep.c_str())) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -278,7 +280,8 @@ void PluginLoader::sortPluginsByDependencies() {
|
||||||
|
|
||||||
// 构建图
|
// 构建图
|
||||||
for (const auto &pair : plugins_) {
|
for (const auto &pair : plugins_) {
|
||||||
if (!pair.second.plugin) continue;
|
if (!pair.second.plugin)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (const auto &dep : pair.second.plugin->getDependencies()) {
|
for (const auto &dep : pair.second.plugin->getDependencies()) {
|
||||||
graph[dep].push_back(pair.first);
|
graph[dep].push_back(pair.first);
|
||||||
|
|
@ -321,26 +324,41 @@ void PluginLoader::sortPluginsByDependencies() {
|
||||||
void *PluginLoader::loadDynamicLibrary(const char *path) {
|
void *PluginLoader::loadDynamicLibrary(const char *path) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return LoadLibraryA(path);
|
return LoadLibraryA(path);
|
||||||
|
#elif defined(__SWITCH__)
|
||||||
|
// Nintendo Switch 平台不支持动态库加载
|
||||||
|
(void)path;
|
||||||
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
return dlopen(path, RTLD_LAZY);
|
return dlopen(path, RTLD_LAZY);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginLoader::unloadDynamicLibrary(void *handle) {
|
void PluginLoader::unloadDynamicLibrary(void *handle) {
|
||||||
if (!handle) return;
|
if (!handle)
|
||||||
|
return;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
FreeLibrary(static_cast<HMODULE>(handle));
|
FreeLibrary(static_cast<HMODULE>(handle));
|
||||||
|
#elif defined(__SWITCH__)
|
||||||
|
// Nintendo Switch 平台不支持动态库加载
|
||||||
|
(void)handle;
|
||||||
#else
|
#else
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void *PluginLoader::getSymbol(void *handle, const char *name) {
|
void *PluginLoader::getSymbol(void *handle, const char *name) {
|
||||||
if (!handle || !name) return nullptr;
|
if (!handle || !name)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle), name));
|
return reinterpret_cast<void *>(
|
||||||
|
GetProcAddress(static_cast<HMODULE>(handle), name));
|
||||||
|
#elif defined(__SWITCH__)
|
||||||
|
// Nintendo Switch 平台不支持动态库加载
|
||||||
|
(void)handle;
|
||||||
|
(void)name;
|
||||||
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
return dlsym(handle, name);
|
return dlsym(handle, name);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,25 @@ bool Logger::consoleOutput_ = true;
|
||||||
bool Logger::fileOutput_ = false;
|
bool Logger::fileOutput_ = false;
|
||||||
std::string Logger::logFile_;
|
std::string Logger::logFile_;
|
||||||
|
|
||||||
|
// Switch 平台:自定义 SDL 日志输出函数
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
/**
|
||||||
|
* @brief Switch 平台日志输出回调函数
|
||||||
|
* @param userdata 用户数据
|
||||||
|
* @param category 日志类别
|
||||||
|
* @param priority 日志优先级
|
||||||
|
* @param message 日志消息
|
||||||
|
*/
|
||||||
|
static void SwitchLogOutput(void *userdata, int category,
|
||||||
|
SDL_LogPriority priority, const char *message) {
|
||||||
|
(void)userdata;
|
||||||
|
(void)category;
|
||||||
|
(void)priority;
|
||||||
|
// 输出到 Switch 控制台
|
||||||
|
printf("%s\n", message);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取日志级别字符串
|
* @brief 获取日志级别字符串
|
||||||
* @param level 日志级别
|
* @param level 日志级别
|
||||||
|
|
@ -41,11 +60,17 @@ void Logger::init() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置 SDL 日志级别为详细模式(允许所有级别的日志)
|
#ifdef __SWITCH__
|
||||||
|
// Switch 平台:初始化控制台并设置 SDL 日志重定向
|
||||||
|
consoleInit(NULL);
|
||||||
|
SDL_LogSetOutputFunction(SwitchLogOutput, nullptr);
|
||||||
|
#else
|
||||||
|
// 其他平台:设置 SDL 日志级别为详细模式
|
||||||
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE);
|
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE);
|
||||||
|
#endif
|
||||||
|
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
log(LogLevel::Info, "Logger initialized with SDL2");
|
log(LogLevel::Info, "Logger initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,6 +79,9 @@ void Logger::init() {
|
||||||
void Logger::shutdown() {
|
void Logger::shutdown() {
|
||||||
if (initialized_) {
|
if (initialized_) {
|
||||||
log(LogLevel::Info, "Logger shutting down");
|
log(LogLevel::Info, "Logger shutting down");
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
consoleExit(NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
initialized_ = false;
|
initialized_ = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -78,7 +78,7 @@ end
|
||||||
-- ==============================================
|
-- ==============================================
|
||||||
|
|
||||||
if target_plat == "mingw" then
|
if target_plat == "mingw" then
|
||||||
add_requires("glm", "libsdl2", "libsdl2_mixer", "vulkansdk")
|
add_requires("glm", "libsdl2", "libsdl2_mixer")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ==============================================
|
-- ==============================================
|
||||||
|
|
|
||||||
|
|
@ -13,24 +13,27 @@ function define_extra2d_engine()
|
||||||
target("extra2d")
|
target("extra2d")
|
||||||
set_kind("static")
|
set_kind("static")
|
||||||
|
|
||||||
add_files("src/**.cpp|core/*.cpp|module/module_manager.cpp|plugin/plugin_manager.cpp|platform/window.cpp|platform/input.cpp")
|
add_files("src/**.cpp")
|
||||||
|
add_files("third_party/glad/src/glad.c")
|
||||||
|
|
||||||
add_includedirs("include", {public = true})
|
add_includedirs("include", {public = true})
|
||||||
add_includedirs("third_party", {public = true})
|
add_includedirs("third_party", {public = true})
|
||||||
|
add_includedirs("third_party/glad/include", {public = true})
|
||||||
|
|
||||||
local plat = get_current_plat()
|
local plat = get_current_plat()
|
||||||
if plat == "mingw" then
|
if plat == "mingw" then
|
||||||
add_defines("_UNICODE", "UNICODE")
|
add_defines("_UNICODE", "UNICODE")
|
||||||
-- 使用 xmake 官方包
|
-- 使用 xmake 官方包
|
||||||
add_packages("glm", "libsdl2", "libsdl2_mixer", "vulkansdk", {public = true})
|
add_packages("glm", "libsdl2", "libsdl2_mixer", {public = true})
|
||||||
add_syslinks("winmm", "imm32", "version", "setupapi", {public = true})
|
add_syslinks("winmm", "imm32", "version", "setupapi", {public = true})
|
||||||
elseif plat == "switch" then
|
elseif plat == "switch" then
|
||||||
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
||||||
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 平台可能需要不同的图形库
|
-- Switch 平台使用 OpenGL ES + EGL + Mesa 驱动
|
||||||
|
-- 注意:链接顺序很重要,被依赖的库要放在后面
|
||||||
add_syslinks("SDL2_mixer", "SDL2", "opusfile", "opus", "vorbisidec", "ogg",
|
add_syslinks("SDL2_mixer", "SDL2", "opusfile", "opus", "vorbisidec", "ogg",
|
||||||
"modplug", "mpg123", "FLAC", "drm_nouveau",
|
"modplug", "mpg123", "FLAC", "GLESv2", "EGL", "glapi", "drm_nouveau",
|
||||||
{public = true})
|
{public = true})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ function define_switch_toolchain()
|
||||||
add_includedirs(path.join(devkitPro, "libnx/include"))
|
add_includedirs(path.join(devkitPro, "libnx/include"))
|
||||||
add_linkdirs(path.join(devkitPro, "libnx/lib"))
|
add_linkdirs(path.join(devkitPro, "libnx/lib"))
|
||||||
|
|
||||||
-- portlibs 路径(EGL + 桌面 OpenGL + SDL2)
|
-- portlibs 路径(OpenGL ES + EGL + SDL2)
|
||||||
add_includedirs(path.join(devkitPro, "portlibs/switch/include"))
|
add_includedirs(path.join(devkitPro, "portlibs/switch/include"))
|
||||||
add_includedirs(path.join(devkitPro, "portlibs/switch/include/SDL2"))
|
add_includedirs(path.join(devkitPro, "portlibs/switch/include/SDL2"))
|
||||||
add_linkdirs(path.join(devkitPro, "portlibs/switch/lib"))
|
add_linkdirs(path.join(devkitPro, "portlibs/switch/lib"))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue