#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace extra2d { /** * @brief 资源管理模块(主流 ECS 风格) * * 设计参考 Bevy/Amethyst: * - AssetStorage: 密集存储资源 * - load(): 统一加载接口 * - Handle: 轻量级句柄 */ class AssetsModule : public Module { E2D_REGISTER_MODULE(AssetsModule, "Assets", 2) public: AssetsModule(); ~AssetsModule() override; bool init() override; void shutdown() override; /** * @brief 在 OpenGL 上下文就绪后创建默认资源 */ void onGLContextReady(); //=========================================================================== // 核心加载接口(模板方法,主流设计) //=========================================================================== /** * @brief 加载资源(自动缓存,重复加载返回已有) * * 示例: * @code * Handle tex = assets->load("player.png"); * Handle shader = assets->load("sprite.vert", "sprite.frag"); * @endcode * * @tparam T 资源类型 * @param path 文件路径 * @return 资源句柄 */ template Handle load(const std::string &path, Args &&...args); /** * @brief 从内存加载资源 * @tparam T 资源类型 * @param key 缓存键名 * @param data 数据指针 * @param size 数据大小 * @return 资源句柄 */ template Handle loadFromMemory(const std::string &key, const uint8_t *data, size_t size); /** * @brief 获取资源(返回指针,可能为 nullptr) * * 示例: * @code * Texture* tex = assets->get(handle); * if (tex) { * tex->bind(); * } * @endcode */ template T *get(Handle handle); /** * @brief 获取资源(返回智能指针) */ template Ptr getPtr(Handle handle); /** * @brief 检查句柄是否有效 */ template bool isValid(Handle handle) const; /** * @brief 移除资源 */ template void remove(Handle handle); //=========================================================================== // 批量加载(目录/包) //=========================================================================== /** * @brief 加载整个目录 * @tparam T 资源类型 * @param directory 目录路径 * @param pattern 文件模式(如 "*.png") * @param recursive 是否递归 * @return 句柄列表 */ template std::vector> loadDir(const std::string &directory, const std::string &pattern = "*", bool recursive = true); //=========================================================================== // 异步加载 //=========================================================================== /** * @brief 异步加载资源 * @tparam T 资源类型 * @param path 文件路径 * @param callback 加载完成回调 */ template void loadAsync(const std::string &path, std::function)> callback); //=========================================================================== // 注册加载器(扩展点) //=========================================================================== /** * @brief 注册资源加载器 * @tparam T 资源类型 * @param loader 加载器实例 */ template void registerLoader(std::unique_ptr> loader); //=========================================================================== // 默认资源 //=========================================================================== /** * @brief 创建默认资源 * @return 是否成功 */ bool createDefaultResources(); /** * @brief 销毁默认资源 */ void destroyDefaultResources(); Handle getDefaultTexture(); Handle getDefaultShader(); Handle getDefaultMaterial(); Handle getDefaultQuad(); Texture *getDefaultTexturePtr(); Shader *getDefaultShaderPtr(); Material *getDefaultMaterialPtr(); Mesh *getDefaultQuadPtr(); //=========================================================================== // 热重载 //=========================================================================== /** * @brief 启用/禁用热重载 * @param enable 是否启用 */ void enableHotReload(bool enable); /** * @brief 检查文件变更并重新加载 */ void checkForChanges(); /** * @brief 设置热重载检查间隔(秒) * @param interval 检查间隔,默认 1.0 秒 */ void setHotReloadInterval(float interval); private: /** * @brief 资源文件监控信息 */ struct FileWatchInfo { std::string path; std::filesystem::file_time_type lastWriteTime; Handle textureHandle; Handle shaderHandle; bool isTexture = false; }; /** * @brief 添加文件监控 */ void addFileWatch(const std::string &path, Handle handle); void addFileWatch(const std::string &path, Handle handle); /** * @brief 重新加载纹理 */ void reloadTexture(const FileWatchInfo &info); /** * @brief 重新加载着色器 */ void reloadShader(const FileWatchInfo &info); public: //=========================================================================== // 统计 //=========================================================================== struct Stats { size_t textureCount = 0; size_t shaderCount = 0; size_t materialCount = 0; size_t meshCount = 0; }; Stats getStats() const; private: // 资源存储 AssetStorage textures_; AssetStorage shaders_; AssetStorage materials_; AssetStorage meshes_; // 加载器 std::unique_ptr> textureLoader_; std::unique_ptr> shaderLoader_; // 路径缓存(避免重复加载) std::unordered_map> texturePathCache_; std::unordered_map> shaderPathCache_; // 默认资源 Handle defaultTexture_; Handle defaultShader_; Handle defaultMaterial_; Handle defaultQuad_; // 热重载 bool hotReloadEnabled_ = false; float hotReloadInterval_ = 1.0f; float hotReloadTimer_ = 0.0f; std::vector fileWatchList_; // 线程安全 mutable std::shared_mutex mutex_; // 事件监听器 std::unique_ptr onShowListener_; // 标记默认资源是否已创建 bool defaultResourcesCreated_ = false; //=========================================================================== // 异步加载系统 //=========================================================================== public: /** * @brief 异步加载任务 */ struct LoadTask { enum class Type { Texture, Shader }; enum class Priority { Low = 0, Normal = 1, High = 2 }; Type type; Priority priority; std::string path; std::string secondaryPath; // 用于着色器的片段着色器路径 std::function)> textureCallback; std::function)> shaderCallback; }; /** * @brief 初始化异步加载系统 * @param threadCount 工作线程数,默认使用硬件并发数 */ void initAsyncLoader(uint32_t threadCount = 0); /** * @brief 关闭异步加载系统 */ void shutdownAsyncLoader(); /** * @brief 提交异步加载任务 */ void submitLoadTask(const LoadTask &task); /** * @brief 处理异步加载队列(在主线程调用) */ void processAsyncCallbacks(); private: // 异步加载队列 std::vector loadQueue_; std::vector workerThreads_; std::mutex queueMutex_; std::condition_variable queueCV_; std::atomic asyncLoaderRunning_{false}; // 完成的回调队列(主线程处理) std::vector> completedCallbacks_; std::mutex callbackMutex_; void workerThreadLoop(); //=========================================================================== // 资源依赖跟踪 //=========================================================================== public: /** * @brief 资源依赖关系 */ struct DependencyInfo { Handle texture; Handle shader; std::vector> dependentMaterials; }; /** * @brief 注册材质对纹理的依赖 */ void registerMaterialDependency(Handle material, Handle texture); /** * @brief 注册材质对着色器的依赖 */ void registerMaterialDependency(Handle material, Handle shader); /** * @brief 当纹理重新加载时通知依赖的材质 */ void notifyTextureReloaded(Handle texture); /** * @brief 当着色器重新加载时通知依赖的材质 */ void notifyShaderReloaded(Handle shader); private: // 资源依赖映射 std::unordered_map textureDependencies_; std::unordered_map shaderDependencies_; std::shared_mutex dependencyMutex_; }; // 全局访问 AssetsModule *getAssets(); //=========================================================================== // 模板实现 //=========================================================================== template Handle AssetsModule::load(const std::string &path, Args &&...args) { static_assert(sizeof...(Args) == 0 || sizeof...(Args) == 1, "load() accepts 0 or 1 additional arguments"); return Handle::invalid(); } template <> Handle AssetsModule::load(const std::string &path); template <> Handle AssetsModule::load(const std::string &path); template <> Handle AssetsModule::load(const std::string &vertPath, const std::string &fragPath); template Handle AssetsModule::loadFromMemory(const std::string &key, const uint8_t *data, size_t size) { return Handle::invalid(); } template <> Handle AssetsModule::loadFromMemory(const std::string &key, const uint8_t *data, size_t size); template T *AssetsModule::get(Handle handle) { return nullptr; } template <> inline Texture *AssetsModule::get(Handle handle) { return textures_.get(handle); } template <> inline Shader *AssetsModule::get(Handle handle) { return shaders_.get(handle); } template <> inline Material *AssetsModule::get(Handle handle) { return materials_.get(handle); } template <> inline Mesh *AssetsModule::get(Handle handle) { return meshes_.get(handle); } template Ptr AssetsModule::getPtr(Handle handle) { return Ptr(); } template <> inline Ptr AssetsModule::getPtr(Handle handle) { return textures_.getPtr(handle); } template <> inline Ptr AssetsModule::getPtr(Handle handle) { return shaders_.getPtr(handle); } template <> inline Ptr AssetsModule::getPtr(Handle handle) { return materials_.getPtr(handle); } template <> inline Ptr AssetsModule::getPtr(Handle handle) { return meshes_.getPtr(handle); } template bool AssetsModule::isValid(Handle handle) const { return false; } template <> inline bool AssetsModule::isValid(Handle handle) const { return textures_.isValid(handle); } template <> inline bool AssetsModule::isValid(Handle handle) const { return shaders_.isValid(handle); } template <> inline bool AssetsModule::isValid(Handle handle) const { return materials_.isValid(handle); } template <> inline bool AssetsModule::isValid(Handle handle) const { return meshes_.isValid(handle); } template void AssetsModule::remove(Handle handle) {} template <> inline void AssetsModule::remove(Handle handle) { textures_.remove(handle); } template <> inline void AssetsModule::remove(Handle handle) { shaders_.remove(handle); } template <> inline void AssetsModule::remove(Handle handle) { materials_.remove(handle); } template <> inline void AssetsModule::remove(Handle handle) { meshes_.remove(handle); } template std::vector> AssetsModule::loadDir(const std::string &directory, const std::string &pattern, bool recursive) { return {}; } template <> std::vector> AssetsModule::loadDir(const std::string &directory, const std::string &pattern, bool recursive); template void AssetsModule::loadAsync(const std::string &path, std::function)> callback) {} template <> void AssetsModule::loadAsync( const std::string &path, std::function)> callback); template void AssetsModule::registerLoader(std::unique_ptr> loader) {} template <> void AssetsModule::registerLoader( std::unique_ptr> loader); template <> void AssetsModule::registerLoader( std::unique_ptr> loader); } // namespace extra2d