refactor(platform): 重构平台兼容层与资源管理
- 移除 platform_compat.h 和 switch_compat.h,改为直接在 extra2d.h 中包含平台特定头文件 - 删除废弃的 FileSystem 类,简化资源路径处理逻辑 - 重构 ResourceManager 移除搜索路径管理,改为简单路径解析 - 优化 Window 类,移除平台判断代码,通过配置控制功能 - 更新示例项目使用新的资源加载方式 - 统一构建输出目录到项目根目录的 build 文件夹 - 添加 PlatformType 枚举支持显式指定平台类型 - 改进 Switch 平台初始化逻辑,支持配置控制
This commit is contained in:
parent
120b272abf
commit
4d81331a57
|
|
@ -21,16 +21,24 @@ class Camera;
|
|||
// ============================================================================
|
||||
// Application 配置
|
||||
// ============================================================================
|
||||
|
||||
enum class PlatformType {
|
||||
Auto = 0,
|
||||
PC,
|
||||
Switch
|
||||
};
|
||||
|
||||
struct AppConfig {
|
||||
String title = "Easy2D Application";
|
||||
int width = 800;
|
||||
int height = 600;
|
||||
bool fullscreen = false;
|
||||
bool resizable = true; // 窗口是否可调整大小
|
||||
bool resizable = true;
|
||||
bool vsync = true;
|
||||
int fpsLimit = 0; // 0 = 不限制
|
||||
int fpsLimit = 0;
|
||||
BackendType renderBackend = BackendType::OpenGL;
|
||||
int msaaSamples = 0;
|
||||
PlatformType platform = PlatformType::Auto;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
// Platform
|
||||
#include <extra2d/platform/window.h>
|
||||
#include <extra2d/platform/input.h>
|
||||
#include <extra2d/platform/file_system.h>
|
||||
|
||||
// Graphics
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
|
|
@ -96,3 +95,7 @@
|
|||
// Script
|
||||
#include <extra2d/script/script_engine.h>
|
||||
#include <extra2d/script/script_node.h>
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file file_system.h
|
||||
* @brief 跨平台文件系统工具
|
||||
*
|
||||
* 提供统一的文件路径处理和文件操作接口
|
||||
* 支持平台: Nintendo Switch, Windows, Linux, macOS
|
||||
*/
|
||||
|
||||
#include <extra2d/platform/platform_compat.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 文件系统工具类
|
||||
// ============================================================================
|
||||
class FileSystem {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取资源根目录
|
||||
* @return 资源根目录路径
|
||||
*
|
||||
* Switch: "romfs:/"
|
||||
* PC: 可执行文件所在目录 + "/assets/" 或当前工作目录
|
||||
*/
|
||||
static std::string getResourceRoot();
|
||||
|
||||
/**
|
||||
* @brief 解析资源路径
|
||||
* @param relativePath 相对路径 (例如 "assets/font.ttf")
|
||||
* @return 完整路径
|
||||
*
|
||||
* Switch: "romfs:/assets/font.ttf"
|
||||
* PC: "./assets/font.ttf" 或 exe目录/assets/font.ttf
|
||||
*/
|
||||
static std::string resolvePath(const std::string& relativePath);
|
||||
|
||||
/**
|
||||
* @brief 检查文件是否存在
|
||||
* @param path 文件路径
|
||||
* @return true 如果文件存在
|
||||
*/
|
||||
static bool fileExists(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 检查目录是否存在
|
||||
* @param path 目录路径
|
||||
* @return true 如果目录存在
|
||||
*/
|
||||
static bool directoryExists(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 获取可执行文件所在目录
|
||||
* @return 可执行文件目录路径
|
||||
*/
|
||||
static std::string getExecutableDirectory();
|
||||
|
||||
/**
|
||||
* @brief 获取当前工作目录
|
||||
* @return 当前工作目录路径
|
||||
*/
|
||||
static std::string getCurrentWorkingDirectory();
|
||||
|
||||
/**
|
||||
* @brief 组合路径
|
||||
* @param base 基础路径
|
||||
* @param relative 相对路径
|
||||
* @return 组合后的路径
|
||||
*/
|
||||
static std::string combinePath(const std::string& base, const std::string& relative);
|
||||
|
||||
/**
|
||||
* @brief 获取文件名(不含路径)
|
||||
* @param path 完整路径
|
||||
* @return 文件名
|
||||
*/
|
||||
static std::string getFileName(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 获取文件扩展名
|
||||
* @param path 文件路径
|
||||
* @return 扩展名(包含点,例如 ".ttf")
|
||||
*/
|
||||
static std::string getFileExtension(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 获取目录名
|
||||
* @param path 文件路径
|
||||
* @return 目录路径
|
||||
*/
|
||||
static std::string getDirectoryName(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 规范化路径(统一分隔符,去除冗余)
|
||||
* @param path 原始路径
|
||||
* @return 规范化后的路径
|
||||
*/
|
||||
static std::string normalizePath(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 读取文件内容为字符串
|
||||
* @param path 文件路径
|
||||
* @return 文件内容,失败返回空字符串
|
||||
*/
|
||||
static std::string readFileText(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 读取文件内容为字节数组
|
||||
* @param path 文件路径
|
||||
* @return 文件内容,失败返回空vector
|
||||
*/
|
||||
static std::vector<uint8_t> readFileBytes(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 获取文件大小
|
||||
* @param path 文件路径
|
||||
* @return 文件大小(字节),失败返回 -1
|
||||
*/
|
||||
static int64_t getFileSize(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 创建目录
|
||||
* @param path 目录路径
|
||||
* @return true 如果成功
|
||||
*/
|
||||
static bool createDirectory(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 创建多级目录
|
||||
* @param path 目录路径
|
||||
* @return true 如果成功
|
||||
*/
|
||||
static bool createDirectories(const std::string& path);
|
||||
|
||||
private:
|
||||
// 禁止实例化
|
||||
FileSystem() = delete;
|
||||
~FileSystem() = delete;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 便捷函数
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 解析资源路径的便捷函数
|
||||
* @param path 相对路径
|
||||
* @return 完整路径
|
||||
*/
|
||||
inline std::string resolvePath(const std::string& path) {
|
||||
return FileSystem::resolvePath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查文件是否存在的便捷函数
|
||||
* @param path 文件路径
|
||||
* @return true 如果文件存在
|
||||
*/
|
||||
inline bool fileExists(const std::string& path) {
|
||||
return FileSystem::fileExists(path);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
#include <array>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/platform/platform_compat.h>
|
||||
#include <extra2d/event/input_codes.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
|
|
|||
|
|
@ -1,263 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file platform_compat.h
|
||||
* @brief 跨平台兼容性头文件
|
||||
*
|
||||
* 提供所有支持平台的兼容性定义和宏
|
||||
* 支持平台: Nintendo Switch, Windows, Linux, macOS
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// 平台检测
|
||||
// ============================================================================
|
||||
|
||||
#ifdef __SWITCH__
|
||||
// Nintendo Switch 平台
|
||||
#define PLATFORM_SWITCH 1
|
||||
#define PLATFORM_NAME "Nintendo Switch"
|
||||
|
||||
#elif defined(_WIN32)
|
||||
// Windows 平台
|
||||
#define PLATFORM_PC 1
|
||||
#define PLATFORM_WINDOWS 1
|
||||
#define PLATFORM_NAME "Windows"
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
// 禁用 SDL 的 main 重定义,使用标准 main 函数
|
||||
#define SDL_MAIN_HANDLED
|
||||
|
||||
#elif defined(__linux__)
|
||||
// Linux 平台
|
||||
#define PLATFORM_PC 1
|
||||
#define PLATFORM_LINUX 1
|
||||
#define PLATFORM_NAME "Linux"
|
||||
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
// macOS 平台
|
||||
#define PLATFORM_PC 1
|
||||
#define PLATFORM_MACOS 1
|
||||
#define PLATFORM_NAME "macOS"
|
||||
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// Nintendo Switch 平台包含
|
||||
// ============================================================================
|
||||
|
||||
#ifdef PLATFORM_SWITCH
|
||||
|
||||
#include <switch.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string>
|
||||
|
||||
// RomFS路径前缀
|
||||
#define ROMFS_PREFIX "romfs:/"
|
||||
|
||||
// Switch 特定的编译器属性
|
||||
#define E2D_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define E2D_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
// Switch 调试输出
|
||||
#ifdef E2D_DEBUG
|
||||
#define E2D_PLATFORM_LOG(fmt, ...) printf("[Extra2D] " fmt "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define E2D_PLATFORM_LOG(fmt, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_SWITCH
|
||||
|
||||
// ============================================================================
|
||||
// PC 平台包含 (Windows/Linux/macOS)
|
||||
// ============================================================================
|
||||
|
||||
#ifdef PLATFORM_PC
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
// PC 平台使用标准文件路径
|
||||
#define ROMFS_PREFIX ""
|
||||
|
||||
// PC 平台编译器属性
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define E2D_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define E2D_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define E2D_LIKELY(x) (x)
|
||||
#define E2D_UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
// PC 调试输出
|
||||
#ifdef E2D_DEBUG
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#define E2D_PLATFORM_LOG(fmt, ...) OutputDebugStringA((std::string("[Extra2D] ") + fmt + "\n").c_str())
|
||||
#else
|
||||
#define E2D_PLATFORM_LOG(fmt, ...) printf("[Extra2D] " fmt "\n", ##__VA_ARGS__)
|
||||
#endif
|
||||
#else
|
||||
#define E2D_PLATFORM_LOG(fmt, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_PC
|
||||
|
||||
// ============================================================================
|
||||
// 跨平台通用定义
|
||||
// ============================================================================
|
||||
|
||||
namespace extra2d {
|
||||
namespace platform {
|
||||
|
||||
/**
|
||||
* @brief 获取当前平台名称
|
||||
* @return 平台名称字符串
|
||||
*/
|
||||
inline const char* getPlatformName() {
|
||||
return PLATFORM_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查当前是否为 Switch 平台
|
||||
* @return true 如果是 Switch 平台
|
||||
*/
|
||||
inline bool isSwitch() {
|
||||
#ifdef PLATFORM_SWITCH
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查当前是否为 PC 平台
|
||||
* @return true 如果是 PC 平台 (Windows/Linux/macOS)
|
||||
*/
|
||||
inline bool isPC() {
|
||||
#ifdef PLATFORM_PC
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查当前是否为 Windows 平台
|
||||
* @return true 如果是 Windows 平台
|
||||
*/
|
||||
inline bool isWindows() {
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查当前是否为 Linux 平台
|
||||
* @return true 如果是 Linux 平台
|
||||
*/
|
||||
inline bool isLinux() {
|
||||
#ifdef PLATFORM_LINUX
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查当前是否为 macOS 平台
|
||||
* @return true 如果是 macOS 平台
|
||||
*/
|
||||
inline bool isMacOS() {
|
||||
#ifdef PLATFORM_MACOS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace platform
|
||||
|
||||
// ============================================================================
|
||||
// 文件系统路径工具
|
||||
// ============================================================================
|
||||
|
||||
namespace romfs {
|
||||
|
||||
/**
|
||||
* @brief RomFS 根路径常量
|
||||
*/
|
||||
#ifdef PLATFORM_SWITCH
|
||||
static constexpr const char* ROOT = "romfs:/";
|
||||
#else
|
||||
static constexpr const char* ROOT = "";
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 检查文件是否存在
|
||||
* @param path 文件路径
|
||||
* @return true 如果文件存在
|
||||
*/
|
||||
inline bool fileExists(const char* path) {
|
||||
struct stat st;
|
||||
return stat(path, &st) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查路径是否为 romfs 路径 (Switch) 或普通路径 (PC)
|
||||
* @param path 文件路径
|
||||
* @return true 如果是 romfs 格式路径
|
||||
*/
|
||||
inline bool isRomfsPath(const char* path) {
|
||||
return path && (strncmp(path, "romfs:/", 7) == 0 || strncmp(path, "romfs:\\", 7) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 构建完整路径
|
||||
* @param relativePath 相对路径
|
||||
* @return 完整路径 (Switch 添加 romfs:/ 前缀,PC 保持原样)
|
||||
*/
|
||||
inline std::string makePath(const char* relativePath) {
|
||||
#ifdef PLATFORM_SWITCH
|
||||
std::string result = ROOT;
|
||||
result += relativePath;
|
||||
return result;
|
||||
#else
|
||||
return std::string(relativePath);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace romfs
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
// ============================================================================
|
||||
// 向后兼容:保留 switch_compat.h 的宏定义
|
||||
// ============================================================================
|
||||
|
||||
#ifdef PLATFORM_SWITCH
|
||||
#define IS_SWITCH_PLATFORM 1
|
||||
#define SWITCH_ROMFS_PREFIX "romfs:/"
|
||||
#define SWITCH_LIKELY(x) E2D_LIKELY(x)
|
||||
#define SWITCH_UNLIKELY(x) E2D_UNLIKELY(x)
|
||||
#ifdef E2D_DEBUG
|
||||
#define SWITCH_DEBUG_PRINTF(fmt, ...) E2D_PLATFORM_LOG(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define SWITCH_DEBUG_PRINTF(fmt, ...) ((void)0)
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file switch_compat.h
|
||||
* @brief Nintendo Switch 兼容性头文件 (已弃用)
|
||||
*
|
||||
* @deprecated 请使用 platform_compat.h 替代
|
||||
* 此文件保留用于向后兼容
|
||||
*/
|
||||
|
||||
// 包含新的跨平台兼容性头文件
|
||||
#include "platform_compat.h"
|
||||
|
||||
// 发出弃用警告(仅在非 Switch 平台或调试模式下)
|
||||
#if !defined(__SWITCH__) && defined(E2D_DEBUG)
|
||||
#warning "switch_compat.h is deprecated, use platform_compat.h instead"
|
||||
#endif
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/core/string.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/platform/platform_compat.h>
|
||||
#include <functional>
|
||||
|
||||
#include <SDL.h>
|
||||
|
|
@ -21,11 +20,13 @@ struct WindowConfig {
|
|||
String title = "Extra2D Application";
|
||||
int width = 1280;
|
||||
int height = 720;
|
||||
bool fullscreen = true; // Switch 始终全屏,PC 可配置
|
||||
bool resizable = false; // PC 端可调整大小
|
||||
bool fullscreen = true;
|
||||
bool resizable = false;
|
||||
bool vsync = true;
|
||||
int msaaSamples = 0;
|
||||
bool centerWindow = true; // PC 端窗口居中
|
||||
bool centerWindow = true;
|
||||
bool enableCursors = true;
|
||||
bool enableDpiScale = true;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -132,6 +133,7 @@ private:
|
|||
bool focused_;
|
||||
float contentScaleX_;
|
||||
float contentScaleY_;
|
||||
bool enableDpiScale_;
|
||||
void* userData_;
|
||||
EventQueue* eventQueue_;
|
||||
UniquePtr<Input> input_;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -22,27 +21,6 @@ public:
|
|||
// ------------------------------------------------------------------------
|
||||
static ResourceManager &getInstance();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 搜索路径管理
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// 添加资源搜索路径
|
||||
void addSearchPath(const std::string &path);
|
||||
|
||||
/// 移除资源搜索路径
|
||||
void removeSearchPath(const std::string &path);
|
||||
|
||||
/// 清空所有搜索路径
|
||||
void clearSearchPaths();
|
||||
|
||||
/// 获取搜索路径列表
|
||||
const std::vector<std::string> &getSearchPaths() const {
|
||||
return searchPaths_;
|
||||
}
|
||||
|
||||
/// 查找资源文件完整路径
|
||||
std::string findResourcePath(const std::string &filename) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 纹理资源
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -83,14 +61,6 @@ public:
|
|||
Ptr<FontAtlas> loadFont(const std::string &filepath, int fontSize,
|
||||
bool useSDF = false);
|
||||
|
||||
/// 尝试从多个候选路径加载字体,返回第一个成功加载的字体
|
||||
Ptr<FontAtlas> loadFontWithFallbacks(const std::vector<std::string> &fontPaths,
|
||||
int fontSize, bool useSDF = false);
|
||||
|
||||
/// 加载字体,使用默认系统字体作为后备
|
||||
Ptr<FontAtlas> loadFontWithDefaultFallback(const std::string &filepath,
|
||||
int fontSize, bool useSDF = false);
|
||||
|
||||
/// 通过key获取已缓存的字体图集
|
||||
Ptr<FontAtlas> getFont(const std::string &key) const;
|
||||
|
||||
|
|
@ -151,9 +121,6 @@ public:
|
|||
mutable std::mutex fontMutex_;
|
||||
mutable std::mutex soundMutex_;
|
||||
|
||||
// 搜索路径
|
||||
std::vector<std::string> searchPaths_;
|
||||
|
||||
// 资源缓存 - 使用弱指针实现自动清理
|
||||
std::unordered_map<std::string, WeakPtr<Texture>> textureCache_;
|
||||
std::unordered_map<std::string, WeakPtr<FontAtlas>> fontCache_;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,17 @@ bool Application::init(const AppConfig &config) {
|
|||
|
||||
config_ = config;
|
||||
|
||||
// 确定平台类型
|
||||
PlatformType platform = config_.platform;
|
||||
if (platform == PlatformType::Auto) {
|
||||
#ifdef __SWITCH__
|
||||
platform = PlatformType::Switch;
|
||||
#else
|
||||
platform = PlatformType::PC;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (platform == PlatformType::Switch) {
|
||||
#ifdef __SWITCH__
|
||||
// ========================================
|
||||
// 1. 初始化 RomFS 文件系统(Switch 平台)
|
||||
|
|
@ -74,6 +85,7 @@ bool Application::init(const AppConfig &config) {
|
|||
"socketInitializeDefault failed, nxlink will not be available");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 3. 创建窗口(包含 SDL_Init + GLES 3.2 上下文创建)
|
||||
|
|
@ -83,14 +95,18 @@ bool Application::init(const AppConfig &config) {
|
|||
winConfig.title = config.title;
|
||||
winConfig.width = 1280;
|
||||
winConfig.height = 720;
|
||||
#ifdef __SWITCH__
|
||||
if (platform == PlatformType::Switch) {
|
||||
winConfig.fullscreen = true;
|
||||
winConfig.resizable = false;
|
||||
#else
|
||||
winConfig.enableCursors = false;
|
||||
winConfig.enableDpiScale = false;
|
||||
} else {
|
||||
// PC 平台默认窗口模式
|
||||
winConfig.fullscreen = config.fullscreen;
|
||||
winConfig.resizable = true;
|
||||
#endif
|
||||
winConfig.enableCursors = true;
|
||||
winConfig.enableDpiScale = true;
|
||||
}
|
||||
winConfig.vsync = config.vsync;
|
||||
winConfig.msaaSamples = config.msaaSamples;
|
||||
|
||||
|
|
@ -138,14 +154,6 @@ bool Application::init(const AppConfig &config) {
|
|||
// 初始化音频引擎
|
||||
AudioEngine::getInstance().initialize();
|
||||
|
||||
#ifdef __SWITCH__
|
||||
// 添加 romfs:/ 到资源搜索路径(Switch 平台)
|
||||
resourceManager_->addSearchPath("romfs:/");
|
||||
#endif
|
||||
// 添加默认资源路径
|
||||
resourceManager_->addSearchPath("assets/");
|
||||
resourceManager_->addSearchPath("./");
|
||||
|
||||
initialized_ = true;
|
||||
running_ = true;
|
||||
|
||||
|
|
@ -185,11 +193,21 @@ void Application::shutdown() {
|
|||
window_.reset();
|
||||
}
|
||||
|
||||
#ifdef __SWITCH__
|
||||
// Switch 平台清理
|
||||
PlatformType platform = config_.platform;
|
||||
if (platform == PlatformType::Auto) {
|
||||
#ifdef __SWITCH__
|
||||
platform = PlatformType::Switch;
|
||||
#else
|
||||
platform = PlatformType::PC;
|
||||
#endif
|
||||
}
|
||||
if (platform == PlatformType::Switch) {
|
||||
#ifdef __SWITCH__
|
||||
romfsExit();
|
||||
socketExit();
|
||||
#endif
|
||||
}
|
||||
|
||||
initialized_ = false;
|
||||
running_ = false;
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
#include <extra2d/graphics/render_command.h>
|
||||
|
||||
namespace extra2d {
|
||||
// This file exists to allow compilation of the render_command header
|
||||
// The RenderCommand struct is header-only for performance
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
#include <extra2d/platform/file_system.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <shlwapi.h>
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 平台特定辅助函数
|
||||
// ============================================================================
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
static const char PATH_SEPARATOR = '\\';
|
||||
static const char PATH_SEPARATOR_ALT = '/';
|
||||
#else
|
||||
static const char PATH_SEPARATOR = '/';
|
||||
static const char PATH_SEPARATOR_ALT = '\\';
|
||||
#endif
|
||||
|
||||
static std::string normalizeSeparators(const std::string& path) {
|
||||
std::string result = path;
|
||||
std::replace(result.begin(), result.end(), PATH_SEPARATOR_ALT, PATH_SEPARATOR);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 资源根目录
|
||||
// ============================================================================
|
||||
|
||||
std::string FileSystem::getResourceRoot() {
|
||||
#ifdef PLATFORM_SWITCH
|
||||
return "romfs:/";
|
||||
#else
|
||||
// PC 端:优先使用可执行文件目录下的 assets 文件夹
|
||||
std::string exeDir = getExecutableDirectory();
|
||||
std::string assetsDir = combinePath(exeDir, "assets");
|
||||
|
||||
if (directoryExists(assetsDir)) {
|
||||
return assetsDir;
|
||||
}
|
||||
|
||||
// 备选:当前工作目录
|
||||
std::string cwd = getCurrentWorkingDirectory();
|
||||
assetsDir = combinePath(cwd, "assets");
|
||||
|
||||
if (directoryExists(assetsDir)) {
|
||||
return assetsDir;
|
||||
}
|
||||
|
||||
// 默认返回当前工作目录
|
||||
return cwd;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 路径解析
|
||||
// ============================================================================
|
||||
|
||||
std::string FileSystem::resolvePath(const std::string& relativePath) {
|
||||
std::string normalized = normalizeSeparators(relativePath);
|
||||
|
||||
#ifdef PLATFORM_SWITCH
|
||||
// Switch: 添加 romfs:/ 前缀
|
||||
if (normalized.find("romfs:/") == 0) {
|
||||
return normalized;
|
||||
}
|
||||
return "romfs:/" + normalized;
|
||||
#else
|
||||
// PC: 如果已经是绝对路径,直接返回
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (normalized.size() >= 2 && normalized[1] == ':') {
|
||||
return normalized;
|
||||
}
|
||||
#else
|
||||
if (!normalized.empty() && normalized[0] == '/') {
|
||||
return normalized;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 组合资源根目录和相对路径
|
||||
return combinePath(getResourceRoot(), normalized);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 文件/目录检查
|
||||
// ============================================================================
|
||||
|
||||
bool FileSystem::fileExists(const std::string& path) {
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) != 0) {
|
||||
return false;
|
||||
}
|
||||
return (st.st_mode & S_IFREG) != 0;
|
||||
}
|
||||
|
||||
bool FileSystem::directoryExists(const std::string& path) {
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) != 0) {
|
||||
return false;
|
||||
}
|
||||
return (st.st_mode & S_IFDIR) != 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 路径操作
|
||||
// ============================================================================
|
||||
|
||||
std::string FileSystem::getExecutableDirectory() {
|
||||
std::string exePath;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
char buffer[MAX_PATH];
|
||||
DWORD len = GetModuleFileNameA(NULL, buffer, MAX_PATH);
|
||||
if (len > 0 && len < MAX_PATH) {
|
||||
exePath = buffer;
|
||||
}
|
||||
#elif defined(PLATFORM_SWITCH)
|
||||
// Switch: 返回当前工作目录(不支持获取可执行文件路径)
|
||||
return getCurrentWorkingDirectory();
|
||||
#else
|
||||
char buffer[PATH_MAX];
|
||||
ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
|
||||
if (len != -1) {
|
||||
buffer[len] = '\0';
|
||||
exePath = buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!exePath.empty()) {
|
||||
size_t lastSep = exePath.find_last_of("/\\");
|
||||
if (lastSep != std::string::npos) {
|
||||
return exePath.substr(0, lastSep);
|
||||
}
|
||||
}
|
||||
|
||||
return getCurrentWorkingDirectory();
|
||||
}
|
||||
|
||||
std::string FileSystem::getCurrentWorkingDirectory() {
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
char buffer[MAX_PATH];
|
||||
DWORD len = GetCurrentDirectoryA(MAX_PATH, buffer);
|
||||
if (len > 0 && len < MAX_PATH) {
|
||||
return std::string(buffer);
|
||||
}
|
||||
#else
|
||||
char buffer[PATH_MAX];
|
||||
if (getcwd(buffer, sizeof(buffer)) != nullptr) {
|
||||
return std::string(buffer);
|
||||
}
|
||||
#endif
|
||||
return ".";
|
||||
}
|
||||
|
||||
std::string FileSystem::combinePath(const std::string& base, const std::string& relative) {
|
||||
if (base.empty()) {
|
||||
return normalizeSeparators(relative);
|
||||
}
|
||||
if (relative.empty()) {
|
||||
return normalizeSeparators(base);
|
||||
}
|
||||
|
||||
std::string result = normalizeSeparators(base);
|
||||
std::string rel = normalizeSeparators(relative);
|
||||
|
||||
// 移除末尾的分隔符
|
||||
while (!result.empty() && result.back() == PATH_SEPARATOR) {
|
||||
result.pop_back();
|
||||
}
|
||||
|
||||
// 移除开头的分隔符
|
||||
size_t relStart = 0;
|
||||
while (relStart < rel.size() && rel[relStart] == PATH_SEPARATOR) {
|
||||
++relStart;
|
||||
}
|
||||
|
||||
if (relStart < rel.size()) {
|
||||
result += PATH_SEPARATOR;
|
||||
result += rel.substr(relStart);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string FileSystem::getFileName(const std::string& path) {
|
||||
std::string normalized = normalizeSeparators(path);
|
||||
size_t lastSep = normalized.find_last_of(PATH_SEPARATOR);
|
||||
if (lastSep != std::string::npos) {
|
||||
return normalized.substr(lastSep + 1);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
std::string FileSystem::getFileExtension(const std::string& path) {
|
||||
std::string fileName = getFileName(path);
|
||||
size_t lastDot = fileName.find_last_of('.');
|
||||
if (lastDot != std::string::npos && lastDot > 0) {
|
||||
return fileName.substr(lastDot);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string FileSystem::getDirectoryName(const std::string& path) {
|
||||
std::string normalized = normalizeSeparators(path);
|
||||
size_t lastSep = normalized.find_last_of(PATH_SEPARATOR);
|
||||
if (lastSep != std::string::npos) {
|
||||
return normalized.substr(0, lastSep);
|
||||
}
|
||||
return ".";
|
||||
}
|
||||
|
||||
std::string FileSystem::normalizePath(const std::string& path) {
|
||||
return normalizeSeparators(path);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 文件读写
|
||||
// ============================================================================
|
||||
|
||||
std::string FileSystem::readFileText(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::in | std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_ERROR("Failed to open file: {}", path);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> FileSystem::readFileBytes(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_ERROR("Failed to open file: {}", path);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> buffer(static_cast<size_t>(size));
|
||||
file.read(reinterpret_cast<char*>(buffer.data()), size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int64_t FileSystem::getFileSize(const std::string& path) {
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int64_t>(st.st_size);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 目录操作
|
||||
// ============================================================================
|
||||
|
||||
bool FileSystem::createDirectory(const std::string& path) {
|
||||
std::string normalized = normalizeSeparators(path);
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
int result = _mkdir(normalized.c_str());
|
||||
#else
|
||||
int result = mkdir(normalized.c_str(), 0755);
|
||||
#endif
|
||||
|
||||
return result == 0 || errno == EEXIST;
|
||||
}
|
||||
|
||||
bool FileSystem::createDirectories(const std::string& path) {
|
||||
std::string normalized = normalizeSeparators(path);
|
||||
|
||||
if (normalized.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 逐级创建目录
|
||||
size_t pos = 0;
|
||||
while (pos < normalized.size()) {
|
||||
pos = normalized.find(PATH_SEPARATOR, pos + 1);
|
||||
if (pos == std::string::npos) {
|
||||
pos = normalized.size();
|
||||
}
|
||||
|
||||
std::string subPath = normalized.substr(0, pos);
|
||||
if (!subPath.empty() && !directoryExists(subPath)) {
|
||||
if (!createDirectory(subPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -13,7 +13,7 @@ Window::Window()
|
|||
: sdlWindow_(nullptr), glContext_(nullptr), currentCursor_(nullptr),
|
||||
width_(1280), height_(720), vsync_(true), shouldClose_(false),
|
||||
fullscreen_(true), focused_(true), contentScaleX_(1.0f), contentScaleY_(1.0f),
|
||||
userData_(nullptr), eventQueue_(nullptr) {
|
||||
enableDpiScale_(true), userData_(nullptr), eventQueue_(nullptr) {
|
||||
// 初始化光标数组
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
sdlCursors_[i] = nullptr;
|
||||
|
|
@ -32,6 +32,7 @@ bool Window::create(const WindowConfig &config) {
|
|||
height_ = config.height;
|
||||
vsync_ = config.vsync;
|
||||
fullscreen_ = config.fullscreen;
|
||||
enableDpiScale_ = config.enableDpiScale;
|
||||
|
||||
// 初始化 SDL2 + 创建窗口 + GL 上下文
|
||||
if (!initSDL(config)) {
|
||||
|
|
@ -43,13 +44,12 @@ bool Window::create(const WindowConfig &config) {
|
|||
input_ = makeUnique<Input>();
|
||||
input_->init();
|
||||
|
||||
// PC 端初始化光标
|
||||
#ifdef PLATFORM_PC
|
||||
// 初始化光标
|
||||
if (config.enableCursors) {
|
||||
initCursors();
|
||||
#endif
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Window created: {}x{} (Platform: {})",
|
||||
width_, height_, platform::getPlatformName());
|
||||
E2D_LOG_INFO("Window created: {}x{}", width_, height_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -79,13 +79,7 @@ bool Window::initSDL(const WindowConfig &config) {
|
|||
// 创建 SDL2 窗口
|
||||
Uint32 windowFlags = SDL_WINDOW_OPENGL;
|
||||
|
||||
#ifdef PLATFORM_SWITCH
|
||||
// Switch 始终全屏
|
||||
windowFlags |= SDL_WINDOW_FULLSCREEN;
|
||||
width_ = 1280;
|
||||
height_ = 720;
|
||||
#else
|
||||
// PC 端根据配置设置
|
||||
// 根据配置设置窗口模式
|
||||
if (config.fullscreen) {
|
||||
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
} else {
|
||||
|
|
@ -95,7 +89,6 @@ bool Window::initSDL(const WindowConfig &config) {
|
|||
// 注意:SDL_WINDOWPOS_CENTERED 是位置参数,不是窗口标志
|
||||
// 窗口居中在 SDL_CreateWindow 的位置参数中处理
|
||||
}
|
||||
#endif
|
||||
|
||||
sdlWindow_ = SDL_CreateWindow(
|
||||
config.title.c_str(),
|
||||
|
|
@ -143,10 +136,10 @@ bool Window::initSDL(const WindowConfig &config) {
|
|||
// 设置 VSync
|
||||
SDL_GL_SetSwapInterval(vsync_ ? 1 : 0);
|
||||
|
||||
// PC 端更新 DPI 缩放
|
||||
#ifndef PLATFORM_SWITCH
|
||||
// 更新 DPI 缩放
|
||||
if (config.enableDpiScale) {
|
||||
updateContentScale();
|
||||
#endif
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("SDL2 + GLES 3.2 initialized successfully");
|
||||
E2D_LOG_INFO("OpenGL Version: {}",
|
||||
|
|
@ -199,9 +192,7 @@ void Window::pollEvents() {
|
|||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
width_ = event.window.data1;
|
||||
height_ = event.window.data2;
|
||||
#ifndef PLATFORM_SWITCH
|
||||
updateContentScale();
|
||||
#endif
|
||||
if (resizeCallback_) {
|
||||
resizeCallback_(width_, height_);
|
||||
}
|
||||
|
|
@ -240,49 +231,31 @@ bool Window::shouldClose() const { return shouldClose_; }
|
|||
void Window::setShouldClose(bool close) { shouldClose_ = close; }
|
||||
|
||||
void Window::setTitle(const String &title) {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
SDL_SetWindowTitle(sdlWindow_, title.c_str());
|
||||
}
|
||||
#else
|
||||
(void)title;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::setSize(int width, int height) {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
SDL_SetWindowSize(sdlWindow_, width, height);
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
#else
|
||||
(void)width;
|
||||
(void)height;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::setPosition(int x, int y) {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
SDL_SetWindowPosition(sdlWindow_, x, y);
|
||||
}
|
||||
#else
|
||||
(void)x;
|
||||
(void)y;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::setFullscreen(bool fullscreen) {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
||||
SDL_SetWindowFullscreen(sdlWindow_, flags);
|
||||
fullscreen_ = fullscreen;
|
||||
}
|
||||
#else
|
||||
(void)fullscreen;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::setVSync(bool enabled) {
|
||||
|
|
@ -291,40 +264,26 @@ void Window::setVSync(bool enabled) {
|
|||
}
|
||||
|
||||
void Window::setResizable(bool resizable) {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
SDL_SetWindowResizable(sdlWindow_, resizable ? SDL_TRUE : SDL_FALSE);
|
||||
}
|
||||
#else
|
||||
(void)resizable;
|
||||
#endif
|
||||
}
|
||||
|
||||
Vec2 Window::getPosition() const {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
int x, y;
|
||||
SDL_GetWindowPosition(sdlWindow_, &x, &y);
|
||||
return Vec2(static_cast<float>(x), static_cast<float>(y));
|
||||
}
|
||||
#endif
|
||||
return Vec2::Zero();
|
||||
}
|
||||
|
||||
float Window::getContentScaleX() const {
|
||||
#ifdef PLATFORM_SWITCH
|
||||
return 1.0f;
|
||||
#else
|
||||
return contentScaleX_;
|
||||
#endif
|
||||
return enableDpiScale_ ? contentScaleX_ : 1.0f;
|
||||
}
|
||||
|
||||
float Window::getContentScaleY() const {
|
||||
#ifdef PLATFORM_SWITCH
|
||||
return 1.0f;
|
||||
#else
|
||||
return contentScaleY_;
|
||||
#endif
|
||||
return enableDpiScale_ ? contentScaleY_ : 1.0f;
|
||||
}
|
||||
|
||||
Vec2 Window::getContentScale() const {
|
||||
|
|
@ -332,27 +291,22 @@ Vec2 Window::getContentScale() const {
|
|||
}
|
||||
|
||||
bool Window::isMinimized() const {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
Uint32 flags = SDL_GetWindowFlags(sdlWindow_);
|
||||
return (flags & SDL_WINDOW_MINIMIZED) != 0;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Window::isMaximized() const {
|
||||
#ifdef PLATFORM_PC
|
||||
if (sdlWindow_) {
|
||||
Uint32 flags = SDL_GetWindowFlags(sdlWindow_);
|
||||
return (flags & SDL_WINDOW_MAXIMIZED) != 0;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::initCursors() {
|
||||
#ifdef PLATFORM_PC
|
||||
sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||
sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||
sdlCursors_[2] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
|
||||
|
|
@ -362,11 +316,9 @@ void Window::initCursors() {
|
|||
sdlCursors_[6] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||
sdlCursors_[7] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||
sdlCursors_[8] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::deinitCursors() {
|
||||
#ifdef PLATFORM_PC
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (sdlCursors_[i]) {
|
||||
SDL_FreeCursor(sdlCursors_[i]);
|
||||
|
|
@ -374,38 +326,26 @@ void Window::deinitCursors() {
|
|||
}
|
||||
}
|
||||
currentCursor_ = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::setCursor(CursorShape shape) {
|
||||
#ifdef PLATFORM_PC
|
||||
int index = static_cast<int>(shape);
|
||||
if (index >= 0 && index < 9 && sdlCursors_[index]) {
|
||||
SDL_SetCursor(sdlCursors_[index]);
|
||||
currentCursor_ = sdlCursors_[index];
|
||||
}
|
||||
#else
|
||||
(void)shape;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::resetCursor() {
|
||||
#ifdef PLATFORM_PC
|
||||
SDL_SetCursor(SDL_GetDefaultCursor());
|
||||
currentCursor_ = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::setMouseVisible(bool visible) {
|
||||
#ifdef PLATFORM_PC
|
||||
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
|
||||
#else
|
||||
(void)visible;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::updateContentScale() {
|
||||
#ifndef PLATFORM_SWITCH
|
||||
if (sdlWindow_) {
|
||||
// 使用 DPI 计算内容缩放比例
|
||||
int displayIndex = SDL_GetWindowDisplayIndex(sdlWindow_);
|
||||
|
|
@ -418,7 +358,6 @@ void Window::updateContentScale() {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -9,50 +9,6 @@
|
|||
|
||||
namespace extra2d {
|
||||
|
||||
ResourceManager::ResourceManager() {
|
||||
#ifdef __SWITCH__
|
||||
addSearchPath("romfs:/");
|
||||
addSearchPath("sdmc:/");
|
||||
#endif
|
||||
}
|
||||
ResourceManager::~ResourceManager() = default;
|
||||
|
||||
ResourceManager &ResourceManager::getInstance() {
|
||||
static ResourceManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 搜索路径管理
|
||||
// ============================================================================
|
||||
|
||||
void ResourceManager::addSearchPath(const std::string &path) {
|
||||
std::lock_guard<std::mutex> lock(textureMutex_);
|
||||
|
||||
// 避免重复添加
|
||||
auto it = std::find(searchPaths_.begin(), searchPaths_.end(), path);
|
||||
if (it == searchPaths_.end()) {
|
||||
searchPaths_.push_back(path);
|
||||
E2D_LOG_DEBUG("ResourceManager: added search path: {}", path);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::removeSearchPath(const std::string &path) {
|
||||
std::lock_guard<std::mutex> lock(textureMutex_);
|
||||
|
||||
auto it = std::find(searchPaths_.begin(), searchPaths_.end(), path);
|
||||
if (it != searchPaths_.end()) {
|
||||
searchPaths_.erase(it);
|
||||
E2D_LOG_DEBUG("ResourceManager: removed search path: {}", path);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::clearSearchPaths() {
|
||||
std::lock_guard<std::mutex> lock(textureMutex_);
|
||||
searchPaths_.clear();
|
||||
E2D_LOG_DEBUG("ResourceManager: cleared all search paths");
|
||||
}
|
||||
|
||||
// 辅助函数:检查文件是否存在
|
||||
static bool fileExists(const std::string &path) {
|
||||
struct stat st;
|
||||
|
|
@ -64,51 +20,41 @@ static bool isRomfsPath(const std::string &path) {
|
|||
return path.find("romfs:/") == 0 || path.find("romfs:\\") == 0;
|
||||
}
|
||||
|
||||
// 辅助函数:拼接路径
|
||||
static std::string joinPath(const std::string &dir,
|
||||
const std::string &filename) {
|
||||
if (dir.empty())
|
||||
return filename;
|
||||
char lastChar = dir.back();
|
||||
if (lastChar == '/' || lastChar == '\\') {
|
||||
return dir + filename;
|
||||
}
|
||||
return dir + "/" + filename;
|
||||
// 解析资源路径(优先尝试 romfs:/ 前缀,然后 sdmc:/)
|
||||
static std::string resolveResourcePath(const std::string &filepath) {
|
||||
// 如果已经是 romfs 或 sdmc 路径,直接返回
|
||||
if (isRomfsPath(filepath) || filepath.find("sdmc:/") == 0) {
|
||||
return filepath;
|
||||
}
|
||||
|
||||
std::string
|
||||
ResourceManager::findResourcePath(const std::string &filename) const {
|
||||
// 首先检查是否是 romfs 路径(Switch 平台)
|
||||
if (isRomfsPath(filename)) {
|
||||
if (fileExists(filename)) {
|
||||
return filename;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 首先检查是否是绝对路径或相对当前目录存在
|
||||
if (fileExists(filename)) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
// 在搜索路径中查找
|
||||
std::lock_guard<std::mutex> lock(textureMutex_);
|
||||
for (const auto &path : searchPaths_) {
|
||||
std::string fullPath = joinPath(path, filename);
|
||||
if (fileExists(fullPath)) {
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
// 最后尝试在 romfs 中查找(自动添加 romfs:/ 前缀)
|
||||
std::string romfsPath = "romfs:/" + filename;
|
||||
// 优先尝试 romfs:/ 前缀的路径(Switch 平台)
|
||||
std::string romfsPath = "romfs:/" + filepath;
|
||||
if (fileExists(romfsPath)) {
|
||||
return romfsPath;
|
||||
}
|
||||
|
||||
// 尝试 sdmc:/ 前缀的路径(Switch SD卡)
|
||||
std::string sdmcPath = "sdmc:/" + filepath;
|
||||
if (fileExists(sdmcPath)) {
|
||||
return sdmcPath;
|
||||
}
|
||||
|
||||
// 如果都不存在,尝试原路径
|
||||
if (fileExists(filepath)) {
|
||||
return filepath;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
ResourceManager::ResourceManager() = default;
|
||||
ResourceManager::~ResourceManager() = default;
|
||||
|
||||
ResourceManager &ResourceManager::getInstance() {
|
||||
static ResourceManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 纹理资源
|
||||
// ============================================================================
|
||||
|
|
@ -127,14 +73,14 @@ Ptr<Texture> ResourceManager::loadTexture(const std::string &filepath) {
|
|||
textureCache_.erase(it);
|
||||
}
|
||||
|
||||
// 查找完整路径
|
||||
std::string fullPath = findResourcePath(filepath);
|
||||
// 解析资源路径(优先尝试 romfs:/ 前缀)
|
||||
std::string fullPath = resolveResourcePath(filepath);
|
||||
if (fullPath.empty()) {
|
||||
E2D_LOG_ERROR("ResourceManager: texture file not found: {}", filepath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 创建新纹理(根据扩展名自动选择加载路径)
|
||||
// 创建新纹理
|
||||
try {
|
||||
auto texture = makePtr<GLTexture>(fullPath);
|
||||
if (!texture->isValid()) {
|
||||
|
|
@ -261,8 +207,8 @@ Ptr<FontAtlas> ResourceManager::loadFont(const std::string &filepath,
|
|||
fontCache_.erase(it);
|
||||
}
|
||||
|
||||
// 查找完整路径
|
||||
std::string fullPath = findResourcePath(filepath);
|
||||
// 解析资源路径(优先尝试 romfs:/ 前缀)
|
||||
std::string fullPath = resolveResourcePath(filepath);
|
||||
if (fullPath.empty()) {
|
||||
E2D_LOG_ERROR("ResourceManager: font file not found: {}", filepath);
|
||||
return nullptr;
|
||||
|
|
@ -313,92 +259,6 @@ void ResourceManager::unloadFont(const std::string &key) {
|
|||
E2D_LOG_DEBUG("ResourceManager: unloaded font: {}", key);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 多字体后备加载
|
||||
// ============================================================================
|
||||
|
||||
Ptr<FontAtlas> ResourceManager::loadFontWithFallbacks(
|
||||
const std::vector<std::string> &fontPaths, int fontSize, bool useSDF) {
|
||||
|
||||
// 尝试加载每一个候选字体
|
||||
for (const auto &fontPath : fontPaths) {
|
||||
auto font = loadFont(fontPath, fontSize, useSDF);
|
||||
if (font) {
|
||||
E2D_LOG_INFO("ResourceManager: successfully loaded font from fallback list: {}",
|
||||
fontPath);
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
E2D_LOG_ERROR("ResourceManager: failed to load any font from fallback list ({} candidates)",
|
||||
fontPaths.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ptr<FontAtlas> ResourceManager::loadFontWithDefaultFallback(
|
||||
const std::string &filepath, int fontSize, bool useSDF) {
|
||||
|
||||
// 首先尝试加载用户指定的字体
|
||||
auto font = loadFont(filepath, fontSize, useSDF);
|
||||
if (font) {
|
||||
return font;
|
||||
}
|
||||
|
||||
E2D_LOG_WARN("ResourceManager: failed to load font '{}', trying system fallbacks...",
|
||||
filepath);
|
||||
|
||||
// 定义系统默认字体候选列表
|
||||
std::vector<std::string> fallbackFonts;
|
||||
|
||||
#ifdef __SWITCH__
|
||||
// Switch 平台默认字体路径
|
||||
fallbackFonts = {
|
||||
"romfs:/assets/font.ttf", // 应用自带字体
|
||||
"romfs:/assets/default.ttf", // 默认字体备选
|
||||
"romfs:/font.ttf", // 根目录字体
|
||||
"sdmc:/switch/fonts/default.ttf", // SD卡字体目录
|
||||
"sdmc:/switch/fonts/font.ttf",
|
||||
};
|
||||
#else
|
||||
// PC 平台系统字体路径(Windows/Linux/macOS)
|
||||
#ifdef _WIN32
|
||||
fallbackFonts = {
|
||||
"C:/Windows/Fonts/arial.ttf",
|
||||
"C:/Windows/Fonts/segoeui.ttf",
|
||||
"C:/Windows/Fonts/calibri.ttf",
|
||||
"C:/Windows/Fonts/tahoma.ttf",
|
||||
"C:/Windows/Fonts/msyh.ttc", // 微软雅黑
|
||||
};
|
||||
#elif __APPLE__
|
||||
fallbackFonts = {
|
||||
"/System/Library/Fonts/Helvetica.ttc",
|
||||
"/System/Library/Fonts/SFNSDisplay.ttf",
|
||||
"/Library/Fonts/Arial.ttf",
|
||||
};
|
||||
#else
|
||||
// Linux
|
||||
fallbackFonts = {
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
"/usr/share/fonts/truetype/freefont/FreeSans.ttf",
|
||||
"/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
|
||||
"/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf",
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 尝试加载后备字体
|
||||
for (const auto &fallbackPath : fallbackFonts) {
|
||||
font = loadFont(fallbackPath, fontSize, useSDF);
|
||||
if (font) {
|
||||
E2D_LOG_INFO("ResourceManager: loaded fallback font: {}", fallbackPath);
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
E2D_LOG_ERROR("ResourceManager: all font fallbacks exhausted, no font available");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 音效资源
|
||||
// ============================================================================
|
||||
|
|
@ -422,8 +282,8 @@ Ptr<Sound> ResourceManager::loadSound(const std::string &name,
|
|||
soundCache_.erase(it);
|
||||
}
|
||||
|
||||
// 查找完整路径
|
||||
std::string fullPath = findResourcePath(filepath);
|
||||
// 解析资源路径(优先尝试 romfs:/ 前缀)
|
||||
std::string fullPath = resolveResourcePath(filepath);
|
||||
if (fullPath.empty()) {
|
||||
E2D_LOG_ERROR("ResourceManager: sound file not found: {}", filepath);
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -123,13 +123,8 @@ private:
|
|||
*/
|
||||
void loadFonts() {
|
||||
auto &resources = Application::instance().resources();
|
||||
|
||||
std::vector<std::string> fontPaths = {
|
||||
"romfs:/assets/font.ttf" // 备选字体
|
||||
};
|
||||
|
||||
titleFont_ = resources.loadFontWithFallbacks(fontPaths, 60, true);
|
||||
infoFont_ = resources.loadFontWithFallbacks(fontPaths, 28, true);
|
||||
titleFont_ = resources.loadFont("assets/font.ttf", 60, true);
|
||||
infoFont_ = resources.loadFont("assets/font.ttf", 28, true);
|
||||
|
||||
if (!titleFont_) {
|
||||
E2D_LOG_WARN("无法加载标题字体");
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
local host_plat = os.host()
|
||||
local target_plat = get_config("plat") or host_plat
|
||||
|
||||
-- 获取当前脚本所在目录(示例根目录)
|
||||
local example_dir = os.scriptdir()
|
||||
|
||||
-- 可执行文件目标
|
||||
target("collision_demo")
|
||||
set_kind("binary")
|
||||
|
|
@ -18,7 +21,7 @@ target("collision_demo")
|
|||
set_plat("switch")
|
||||
set_arch("arm64")
|
||||
set_toolchains("switch")
|
||||
set_targetdir("build/switch")
|
||||
set_targetdir("../../build/examples/collision_demo")
|
||||
|
||||
after_build(function (target)
|
||||
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
||||
|
|
@ -31,7 +34,7 @@ target("collision_demo")
|
|||
|
||||
if os.isfile(nacptool) and os.isfile(elf2nro) then
|
||||
os.vrunv(nacptool, {"--create", "Collision Demo", "Extra2D Team", "1.0.0", nacp_file})
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
os.vrunv(elf2nro, {elf_file, nro_file, "--nacp=" .. nacp_file, "--romfsdir=" .. romfs})
|
||||
else
|
||||
|
|
@ -43,11 +46,12 @@ target("collision_demo")
|
|||
elseif target_plat == "mingw" then
|
||||
set_plat("mingw")
|
||||
set_arch("x86_64")
|
||||
set_targetdir("build/mingw")
|
||||
set_targetdir("../../build/examples/collision_demo")
|
||||
add_ldflags("-mwindows", {force = true})
|
||||
|
||||
-- 复制资源
|
||||
after_build(function (target)
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
local target_dir = path.directory(target:targetfile())
|
||||
local assets_dir = path.join(target_dir, "assets")
|
||||
|
|
@ -55,6 +59,9 @@ target("collision_demo")
|
|||
os.mkdir(assets_dir)
|
||||
end
|
||||
os.cp(path.join(romfs, "assets/*"), assets_dir)
|
||||
print("Copied assets from " .. romfs .. " to " .. assets_dir)
|
||||
else
|
||||
print("Warning: romfs directory not found at " .. romfs)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ int main(int argc, char **argv)
|
|||
|
||||
E2D_LOG_INFO("========================");
|
||||
E2D_LOG_INFO("Easy2D Hello World Demo");
|
||||
E2D_LOG_INFO("Platform: {}", platform::getPlatformName());
|
||||
E2D_LOG_INFO("========================");
|
||||
|
||||
// 获取应用实例
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
local host_plat = os.host()
|
||||
local target_plat = get_config("plat") or host_plat
|
||||
|
||||
-- 获取当前脚本所在目录(示例根目录)
|
||||
local example_dir = os.scriptdir()
|
||||
|
||||
-- 可执行文件目标
|
||||
target("hello_world")
|
||||
set_kind("binary")
|
||||
|
|
@ -18,7 +21,7 @@ target("hello_world")
|
|||
set_plat("switch")
|
||||
set_arch("arm64")
|
||||
set_toolchains("switch")
|
||||
set_targetdir("build/switch")
|
||||
set_targetdir("../../build/examples/hello_world")
|
||||
|
||||
-- 生成 NRO
|
||||
after_build(function (target)
|
||||
|
|
@ -32,7 +35,7 @@ target("hello_world")
|
|||
|
||||
if os.isfile(nacptool) and os.isfile(elf2nro) then
|
||||
os.vrunv(nacptool, {"--create", "Hello World", "Extra2D Team", "1.0.0", nacp_file})
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
os.vrunv(elf2nro, {elf_file, nro_file, "--nacp=" .. nacp_file, "--romfsdir=" .. romfs})
|
||||
else
|
||||
|
|
@ -44,12 +47,12 @@ target("hello_world")
|
|||
elseif target_plat == "mingw" then
|
||||
set_plat("mingw")
|
||||
set_arch("x86_64")
|
||||
set_targetdir("build/mingw")
|
||||
set_targetdir("../../build/examples/hello_world")
|
||||
add_ldflags("-mwindows", {force = true})
|
||||
|
||||
-- 复制资源
|
||||
after_build(function (target)
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
local target_dir = path.directory(target:targetfile())
|
||||
local assets_dir = path.join(target_dir, "assets")
|
||||
|
|
@ -57,6 +60,9 @@ target("hello_world")
|
|||
os.mkdir(assets_dir)
|
||||
end
|
||||
os.cp(path.join(romfs, "assets/*"), assets_dir)
|
||||
print("Copied assets from " .. romfs .. " to " .. assets_dir)
|
||||
else
|
||||
print("Warning: romfs directory not found at " .. romfs)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ StartScene::StartScene() {
|
|||
|
||||
static extra2d::Ptr<extra2d::FontAtlas> loadMenuFont() {
|
||||
auto& resources = extra2d::Application::instance().resources();
|
||||
auto font = resources.loadFont("assets/font.ttf", 28);
|
||||
auto font = resources.loadFont("assets/font.ttf", 28,true);
|
||||
return font;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ int main(int argc, char **argv)
|
|||
|
||||
E2D_LOG_INFO("========================");
|
||||
E2D_LOG_INFO("Extra2D push_box");
|
||||
E2D_LOG_INFO("Platform: {}", platform::getPlatformName());
|
||||
E2D_LOG_INFO("========================");
|
||||
|
||||
auto &app = Application::instance();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
local host_plat = os.host()
|
||||
local target_plat = get_config("plat") or host_plat
|
||||
|
||||
-- 获取当前脚本所在目录(示例根目录)
|
||||
local example_dir = os.scriptdir()
|
||||
|
||||
-- 可执行文件目标
|
||||
target("push_box")
|
||||
set_kind("binary")
|
||||
|
|
@ -18,7 +21,7 @@ target("push_box")
|
|||
set_plat("switch")
|
||||
set_arch("arm64")
|
||||
set_toolchains("switch")
|
||||
set_targetdir("build/switch")
|
||||
set_targetdir("../../build/examples/push_box")
|
||||
|
||||
after_build(function (target)
|
||||
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
||||
|
|
@ -31,7 +34,7 @@ target("push_box")
|
|||
|
||||
if os.isfile(nacptool) and os.isfile(elf2nro) then
|
||||
os.vrunv(nacptool, {"--create", "Push Box", "Extra2D Team", "1.0.0", nacp_file})
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
os.vrunv(elf2nro, {elf_file, nro_file, "--nacp=" .. nacp_file, "--romfsdir=" .. romfs})
|
||||
else
|
||||
|
|
@ -43,11 +46,12 @@ target("push_box")
|
|||
elseif target_plat == "mingw" then
|
||||
set_plat("mingw")
|
||||
set_arch("x86_64")
|
||||
set_targetdir("build/mingw")
|
||||
set_targetdir("../../build/examples/push_box")
|
||||
add_ldflags("-mwindows", {force = true})
|
||||
|
||||
-- 复制资源
|
||||
after_build(function (target)
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
local target_dir = path.directory(target:targetfile())
|
||||
local assets_dir = path.join(target_dir, "assets")
|
||||
|
|
@ -55,6 +59,9 @@ target("push_box")
|
|||
os.mkdir(assets_dir)
|
||||
end
|
||||
os.cp(path.join(romfs, "assets/*"), assets_dir)
|
||||
print("Copied assets from " .. romfs .. " to " .. assets_dir)
|
||||
else
|
||||
print("Warning: romfs directory not found at " .. romfs)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -185,14 +185,8 @@ private:
|
|||
void loadFonts() {
|
||||
auto &resources = Application::instance().resources();
|
||||
|
||||
std::vector<std::string> fontPaths = {
|
||||
"romfs:/assets/msjh.ttf",
|
||||
"romfs:/assets/default.ttf",
|
||||
"romfs:/assets/font.ttf",
|
||||
};
|
||||
|
||||
titleFont_ = resources.loadFontWithFallbacks(fontPaths, 28, true);
|
||||
infoFont_ = resources.loadFontWithFallbacks(fontPaths, 16, true);
|
||||
titleFont_ = resources.loadFont("assets/font.ttf", 28, true);
|
||||
infoFont_ = resources.loadFont("assets/font.ttf", 16, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
local host_plat = os.host()
|
||||
local target_plat = get_config("plat") or host_plat
|
||||
|
||||
-- 获取当前脚本所在目录(示例根目录)
|
||||
local example_dir = os.scriptdir()
|
||||
|
||||
-- 可执行文件目标
|
||||
target("spatial_index_demo")
|
||||
set_kind("binary")
|
||||
|
|
@ -18,7 +21,7 @@ target("spatial_index_demo")
|
|||
set_plat("switch")
|
||||
set_arch("arm64")
|
||||
set_toolchains("switch")
|
||||
set_targetdir("build/switch")
|
||||
set_targetdir("../../build/examples/spatial_index_demo")
|
||||
|
||||
after_build(function (target)
|
||||
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
||||
|
|
@ -31,7 +34,7 @@ target("spatial_index_demo")
|
|||
|
||||
if os.isfile(nacptool) and os.isfile(elf2nro) then
|
||||
os.vrunv(nacptool, {"--create", "Spatial Index Demo", "Extra2D Team", "1.0.0", nacp_file})
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
os.vrunv(elf2nro, {elf_file, nro_file, "--nacp=" .. nacp_file, "--romfsdir=" .. romfs})
|
||||
else
|
||||
|
|
@ -43,11 +46,12 @@ target("spatial_index_demo")
|
|||
elseif target_plat == "mingw" then
|
||||
set_plat("mingw")
|
||||
set_arch("x86_64")
|
||||
set_targetdir("build/mingw")
|
||||
set_targetdir("../../build/examples/spatial_index_demo")
|
||||
add_ldflags("-mwindows", {force = true})
|
||||
|
||||
-- 复制资源
|
||||
after_build(function (target)
|
||||
local romfs = path.absolute("romfs")
|
||||
local romfs = path.join(example_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
local target_dir = path.directory(target:targetfile())
|
||||
local assets_dir = path.join(target_dir, "assets")
|
||||
|
|
@ -55,6 +59,9 @@ target("spatial_index_demo")
|
|||
os.mkdir(assets_dir)
|
||||
end
|
||||
os.cp(path.join(romfs, "assets/*"), assets_dir)
|
||||
print("Copied assets from " .. romfs .. " to " .. assets_dir)
|
||||
else
|
||||
print("Warning: romfs directory not found at " .. romfs)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue