feat(assets): 实现资源热重载和异步加载系统
添加资源热重载功能,支持监控文件变更并自动重新加载 实现异步加载系统,支持多线程资源加载和回调处理 增加资源依赖跟踪机制,自动更新依赖材质的引用 使用读写锁保护资源存储,提升多线程访问性能
This commit is contained in:
parent
46ec1c665f
commit
f7e4f89cca
|
|
@ -1,19 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <event/events.h>
|
||||
#include <module/module.h>
|
||||
#include <module/module_registry.h>
|
||||
#include <assets/handle.h>
|
||||
#include <assets/asset_storage.h>
|
||||
#include <assets/asset_loader.h>
|
||||
#include <renderer/texture.h>
|
||||
#include <renderer/shader.h>
|
||||
#include <renderer/material.h>
|
||||
#include <renderer/mesh.h>
|
||||
#include <assets/asset_storage.h>
|
||||
#include <assets/handle.h>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <event/events.h>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <module/module.h>
|
||||
#include <module/module_registry.h>
|
||||
#include <mutex>
|
||||
#include <renderer/material.h>
|
||||
#include <renderer/mesh.h>
|
||||
#include <renderer/shader.h>
|
||||
#include <renderer/texture.h>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -28,372 +34,490 @@ namespace extra2d {
|
|||
* - Handle<T>: 轻量级句柄
|
||||
*/
|
||||
class AssetsModule : public Module {
|
||||
E2D_REGISTER_MODULE(AssetsModule, "Assets", 2)
|
||||
E2D_REGISTER_MODULE(AssetsModule, "Assets", 2)
|
||||
|
||||
public:
|
||||
AssetsModule();
|
||||
~AssetsModule() override;
|
||||
AssetsModule();
|
||||
~AssetsModule() override;
|
||||
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
|
||||
/**
|
||||
* @brief 在 OpenGL 上下文就绪后创建默认资源
|
||||
*/
|
||||
void onGLContextReady();
|
||||
/**
|
||||
* @brief 在 OpenGL 上下文就绪后创建默认资源
|
||||
*/
|
||||
void onGLContextReady();
|
||||
|
||||
//===========================================================================
|
||||
// 核心加载接口(模板方法,主流设计)
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
// 核心加载接口(模板方法,主流设计)
|
||||
//===========================================================================
|
||||
|
||||
/**
|
||||
* @brief 加载资源(自动缓存,重复加载返回已有)
|
||||
*
|
||||
* 示例:
|
||||
* @code
|
||||
* Handle<Texture> tex = assets->load<Texture>("player.png");
|
||||
* Handle<Shader> shader = assets->load<Shader>("sprite.vert", "sprite.frag");
|
||||
* @endcode
|
||||
*
|
||||
* @tparam T 资源类型
|
||||
* @param path 文件路径
|
||||
* @return 资源句柄
|
||||
*/
|
||||
template<typename T, typename... Args>
|
||||
Handle<T> load(const std::string& path, Args&&... args);
|
||||
/**
|
||||
* @brief 加载资源(自动缓存,重复加载返回已有)
|
||||
*
|
||||
* 示例:
|
||||
* @code
|
||||
* Handle<Texture> tex = assets->load<Texture>("player.png");
|
||||
* Handle<Shader> shader = assets->load<Shader>("sprite.vert", "sprite.frag");
|
||||
* @endcode
|
||||
*
|
||||
* @tparam T 资源类型
|
||||
* @param path 文件路径
|
||||
* @return 资源句柄
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
Handle<T> load(const std::string &path, Args &&...args);
|
||||
|
||||
/**
|
||||
* @brief 从内存加载资源
|
||||
* @tparam T 资源类型
|
||||
* @param key 缓存键名
|
||||
* @param data 数据指针
|
||||
* @param size 数据大小
|
||||
* @return 资源句柄
|
||||
*/
|
||||
template<typename T>
|
||||
Handle<T> loadFromMemory(const std::string& key, const uint8_t* data, size_t size);
|
||||
/**
|
||||
* @brief 从内存加载资源
|
||||
* @tparam T 资源类型
|
||||
* @param key 缓存键名
|
||||
* @param data 数据指针
|
||||
* @param size 数据大小
|
||||
* @return 资源句柄
|
||||
*/
|
||||
template <typename T>
|
||||
Handle<T> 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<typename T>
|
||||
T* get(Handle<T> handle);
|
||||
/**
|
||||
* @brief 获取资源(返回指针,可能为 nullptr)
|
||||
*
|
||||
* 示例:
|
||||
* @code
|
||||
* Texture* tex = assets->get(handle);
|
||||
* if (tex) {
|
||||
* tex->bind();
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T> T *get(Handle<T> handle);
|
||||
|
||||
/**
|
||||
* @brief 获取资源(返回智能指针)
|
||||
*/
|
||||
template<typename T>
|
||||
Ptr<T> getPtr(Handle<T> handle);
|
||||
/**
|
||||
* @brief 获取资源(返回智能指针)
|
||||
*/
|
||||
template <typename T> Ptr<T> getPtr(Handle<T> handle);
|
||||
|
||||
/**
|
||||
* @brief 检查句柄是否有效
|
||||
*/
|
||||
template<typename T>
|
||||
bool isValid(Handle<T> handle) const;
|
||||
/**
|
||||
* @brief 检查句柄是否有效
|
||||
*/
|
||||
template <typename T> bool isValid(Handle<T> handle) const;
|
||||
|
||||
/**
|
||||
* @brief 移除资源
|
||||
*/
|
||||
template<typename T>
|
||||
void remove(Handle<T> handle);
|
||||
/**
|
||||
* @brief 移除资源
|
||||
*/
|
||||
template <typename T> void remove(Handle<T> handle);
|
||||
|
||||
//===========================================================================
|
||||
// 批量加载(目录/包)
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
// 批量加载(目录/包)
|
||||
//===========================================================================
|
||||
|
||||
/**
|
||||
* @brief 加载整个目录
|
||||
* @tparam T 资源类型
|
||||
* @param directory 目录路径
|
||||
* @param pattern 文件模式(如 "*.png")
|
||||
* @param recursive 是否递归
|
||||
* @return 句柄列表
|
||||
*/
|
||||
template<typename T>
|
||||
std::vector<Handle<T>> loadDir(const std::string& directory,
|
||||
const std::string& pattern = "*",
|
||||
bool recursive = true);
|
||||
/**
|
||||
* @brief 加载整个目录
|
||||
* @tparam T 资源类型
|
||||
* @param directory 目录路径
|
||||
* @param pattern 文件模式(如 "*.png")
|
||||
* @param recursive 是否递归
|
||||
* @return 句柄列表
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<Handle<T>> loadDir(const std::string &directory,
|
||||
const std::string &pattern = "*",
|
||||
bool recursive = true);
|
||||
|
||||
//===========================================================================
|
||||
// 异步加载
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
// 异步加载
|
||||
//===========================================================================
|
||||
|
||||
/**
|
||||
* @brief 异步加载资源
|
||||
* @tparam T 资源类型
|
||||
* @param path 文件路径
|
||||
* @param callback 加载完成回调
|
||||
*/
|
||||
template<typename T>
|
||||
void loadAsync(const std::string& path,
|
||||
std::function<void(Handle<T>)> callback);
|
||||
/**
|
||||
* @brief 异步加载资源
|
||||
* @tparam T 资源类型
|
||||
* @param path 文件路径
|
||||
* @param callback 加载完成回调
|
||||
*/
|
||||
template <typename T>
|
||||
void loadAsync(const std::string &path,
|
||||
std::function<void(Handle<T>)> callback);
|
||||
|
||||
//===========================================================================
|
||||
// 注册加载器(扩展点)
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
// 注册加载器(扩展点)
|
||||
//===========================================================================
|
||||
|
||||
/**
|
||||
* @brief 注册资源加载器
|
||||
* @tparam T 资源类型
|
||||
* @param loader 加载器实例
|
||||
*/
|
||||
template<typename T>
|
||||
void registerLoader(std::unique_ptr<AssetLoader<T>> loader);
|
||||
/**
|
||||
* @brief 注册资源加载器
|
||||
* @tparam T 资源类型
|
||||
* @param loader 加载器实例
|
||||
*/
|
||||
template <typename T>
|
||||
void registerLoader(std::unique_ptr<AssetLoader<T>> loader);
|
||||
|
||||
//===========================================================================
|
||||
// 默认资源
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
// 默认资源
|
||||
//===========================================================================
|
||||
|
||||
/**
|
||||
* @brief 创建默认资源
|
||||
* @return 是否成功
|
||||
*/
|
||||
bool createDefaultResources();
|
||||
/**
|
||||
* @brief 创建默认资源
|
||||
* @return 是否成功
|
||||
*/
|
||||
bool createDefaultResources();
|
||||
|
||||
/**
|
||||
* @brief 销毁默认资源
|
||||
*/
|
||||
void destroyDefaultResources();
|
||||
/**
|
||||
* @brief 销毁默认资源
|
||||
*/
|
||||
void destroyDefaultResources();
|
||||
|
||||
Handle<Texture> getDefaultTexture();
|
||||
Handle<Shader> getDefaultShader();
|
||||
Handle<Material> getDefaultMaterial();
|
||||
Handle<Mesh> getDefaultQuad();
|
||||
Handle<Texture> getDefaultTexture();
|
||||
Handle<Shader> getDefaultShader();
|
||||
Handle<Material> getDefaultMaterial();
|
||||
Handle<Mesh> getDefaultQuad();
|
||||
|
||||
Texture* getDefaultTexturePtr();
|
||||
Shader* getDefaultShaderPtr();
|
||||
Material* getDefaultMaterialPtr();
|
||||
Mesh* getDefaultQuadPtr();
|
||||
Texture *getDefaultTexturePtr();
|
||||
Shader *getDefaultShaderPtr();
|
||||
Material *getDefaultMaterialPtr();
|
||||
Mesh *getDefaultQuadPtr();
|
||||
|
||||
//===========================================================================
|
||||
// 热重载
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
// 热重载
|
||||
//===========================================================================
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用热重载
|
||||
* @param enable 是否启用
|
||||
*/
|
||||
void enableHotReload(bool enable);
|
||||
/**
|
||||
* @brief 启用/禁用热重载
|
||||
* @param enable 是否启用
|
||||
*/
|
||||
void enableHotReload(bool enable);
|
||||
|
||||
/**
|
||||
* @brief 检查文件变更并重新加载
|
||||
*/
|
||||
void checkForChanges();
|
||||
/**
|
||||
* @brief 检查文件变更并重新加载
|
||||
*/
|
||||
void checkForChanges();
|
||||
|
||||
//===========================================================================
|
||||
// 统计
|
||||
//===========================================================================
|
||||
|
||||
struct Stats {
|
||||
size_t textureCount = 0;
|
||||
size_t shaderCount = 0;
|
||||
size_t materialCount = 0;
|
||||
size_t meshCount = 0;
|
||||
};
|
||||
|
||||
Stats getStats() const;
|
||||
/**
|
||||
* @brief 设置热重载检查间隔(秒)
|
||||
* @param interval 检查间隔,默认 1.0 秒
|
||||
*/
|
||||
void setHotReloadInterval(float interval);
|
||||
|
||||
private:
|
||||
// 资源存储
|
||||
AssetStorage<Texture> textures_;
|
||||
AssetStorage<Shader> shaders_;
|
||||
AssetStorage<Material> materials_;
|
||||
AssetStorage<Mesh> meshes_;
|
||||
/**
|
||||
* @brief 资源文件监控信息
|
||||
*/
|
||||
struct FileWatchInfo {
|
||||
std::string path;
|
||||
std::filesystem::file_time_type lastWriteTime;
|
||||
Handle<Texture> textureHandle;
|
||||
Handle<Shader> shaderHandle;
|
||||
bool isTexture = false;
|
||||
};
|
||||
|
||||
// 加载器
|
||||
std::unique_ptr<AssetLoader<Texture>> textureLoader_;
|
||||
std::unique_ptr<AssetLoader<Shader>> shaderLoader_;
|
||||
/**
|
||||
* @brief 添加文件监控
|
||||
*/
|
||||
void addFileWatch(const std::string &path, Handle<Texture> handle);
|
||||
void addFileWatch(const std::string &path, Handle<Shader> handle);
|
||||
|
||||
// 路径缓存(避免重复加载)
|
||||
std::unordered_map<std::string, Handle<Texture>> texturePathCache_;
|
||||
std::unordered_map<std::string, Handle<Shader>> shaderPathCache_;
|
||||
/**
|
||||
* @brief 重新加载纹理
|
||||
*/
|
||||
void reloadTexture(const FileWatchInfo &info);
|
||||
|
||||
// 默认资源
|
||||
Handle<Texture> defaultTexture_;
|
||||
Handle<Shader> defaultShader_;
|
||||
Handle<Material> defaultMaterial_;
|
||||
Handle<Mesh> defaultQuad_;
|
||||
/**
|
||||
* @brief 重新加载着色器
|
||||
*/
|
||||
void reloadShader(const FileWatchInfo &info);
|
||||
|
||||
// 热重载
|
||||
bool hotReloadEnabled_ = false;
|
||||
public:
|
||||
//===========================================================================
|
||||
// 统计
|
||||
//===========================================================================
|
||||
|
||||
// 线程安全
|
||||
mutable std::mutex mutex_;
|
||||
struct Stats {
|
||||
size_t textureCount = 0;
|
||||
size_t shaderCount = 0;
|
||||
size_t materialCount = 0;
|
||||
size_t meshCount = 0;
|
||||
};
|
||||
|
||||
// 事件监听器
|
||||
std::unique_ptr<events::OnShow::Listener> onShowListener_;
|
||||
Stats getStats() const;
|
||||
|
||||
// 标记默认资源是否已创建
|
||||
bool defaultResourcesCreated_ = false;
|
||||
private:
|
||||
// 资源存储
|
||||
AssetStorage<Texture> textures_;
|
||||
AssetStorage<Shader> shaders_;
|
||||
AssetStorage<Material> materials_;
|
||||
AssetStorage<Mesh> meshes_;
|
||||
|
||||
// 加载器
|
||||
std::unique_ptr<AssetLoader<Texture>> textureLoader_;
|
||||
std::unique_ptr<AssetLoader<Shader>> shaderLoader_;
|
||||
|
||||
// 路径缓存(避免重复加载)
|
||||
std::unordered_map<std::string, Handle<Texture>> texturePathCache_;
|
||||
std::unordered_map<std::string, Handle<Shader>> shaderPathCache_;
|
||||
|
||||
// 默认资源
|
||||
Handle<Texture> defaultTexture_;
|
||||
Handle<Shader> defaultShader_;
|
||||
Handle<Material> defaultMaterial_;
|
||||
Handle<Mesh> defaultQuad_;
|
||||
|
||||
// 热重载
|
||||
bool hotReloadEnabled_ = false;
|
||||
float hotReloadInterval_ = 1.0f;
|
||||
float hotReloadTimer_ = 0.0f;
|
||||
std::vector<FileWatchInfo> fileWatchList_;
|
||||
|
||||
// 线程安全
|
||||
mutable std::shared_mutex mutex_;
|
||||
|
||||
// 事件监听器
|
||||
std::unique_ptr<events::OnShow::Listener> 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<void(Handle<Texture>)> textureCallback;
|
||||
std::function<void(Handle<Shader>)> 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<LoadTask> loadQueue_;
|
||||
std::vector<std::thread> workerThreads_;
|
||||
std::mutex queueMutex_;
|
||||
std::condition_variable queueCV_;
|
||||
std::atomic<bool> asyncLoaderRunning_{false};
|
||||
|
||||
// 完成的回调队列(主线程处理)
|
||||
std::vector<std::function<void()>> completedCallbacks_;
|
||||
std::mutex callbackMutex_;
|
||||
|
||||
void workerThreadLoop();
|
||||
|
||||
//===========================================================================
|
||||
// 资源依赖跟踪
|
||||
//===========================================================================
|
||||
public:
|
||||
/**
|
||||
* @brief 资源依赖关系
|
||||
*/
|
||||
struct DependencyInfo {
|
||||
Handle<Texture> texture;
|
||||
Handle<Shader> shader;
|
||||
std::vector<Handle<Material>> dependentMaterials;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 注册材质对纹理的依赖
|
||||
*/
|
||||
void registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Texture> texture);
|
||||
|
||||
/**
|
||||
* @brief 注册材质对着色器的依赖
|
||||
*/
|
||||
void registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Shader> shader);
|
||||
|
||||
/**
|
||||
* @brief 当纹理重新加载时通知依赖的材质
|
||||
*/
|
||||
void notifyTextureReloaded(Handle<Texture> texture);
|
||||
|
||||
/**
|
||||
* @brief 当着色器重新加载时通知依赖的材质
|
||||
*/
|
||||
void notifyShaderReloaded(Handle<Shader> shader);
|
||||
|
||||
private:
|
||||
// 资源依赖映射
|
||||
std::unordered_map<uint32_t, DependencyInfo> textureDependencies_;
|
||||
std::unordered_map<uint32_t, DependencyInfo> shaderDependencies_;
|
||||
std::shared_mutex dependencyMutex_;
|
||||
};
|
||||
|
||||
// 全局访问
|
||||
AssetsModule* getAssets();
|
||||
AssetsModule *getAssets();
|
||||
|
||||
//===========================================================================
|
||||
// 模板实现
|
||||
//===========================================================================
|
||||
|
||||
template<typename T, typename... Args>
|
||||
Handle<T> 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<T>::invalid();
|
||||
template <typename T, typename... Args>
|
||||
Handle<T> 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<T>::invalid();
|
||||
}
|
||||
|
||||
template<>
|
||||
Handle<Texture> AssetsModule::load<Texture>(const std::string& path);
|
||||
template <>
|
||||
Handle<Texture> AssetsModule::load<Texture>(const std::string &path);
|
||||
|
||||
template<>
|
||||
Handle<Shader> AssetsModule::load<Shader>(const std::string& path);
|
||||
template <> Handle<Shader> AssetsModule::load<Shader>(const std::string &path);
|
||||
|
||||
template<>
|
||||
Handle<Shader> AssetsModule::load<Shader>(const std::string& vertPath, const std::string& fragPath);
|
||||
template <>
|
||||
Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
|
||||
const std::string &fragPath);
|
||||
|
||||
template<typename T>
|
||||
Handle<T> AssetsModule::loadFromMemory(const std::string& key, const uint8_t* data, size_t size) {
|
||||
return Handle<T>::invalid();
|
||||
template <typename T>
|
||||
Handle<T> AssetsModule::loadFromMemory(const std::string &key,
|
||||
const uint8_t *data, size_t size) {
|
||||
return Handle<T>::invalid();
|
||||
}
|
||||
|
||||
template<>
|
||||
Handle<Texture> AssetsModule::loadFromMemory<Texture>(const std::string& key, const uint8_t* data, size_t size);
|
||||
template <>
|
||||
Handle<Texture> AssetsModule::loadFromMemory<Texture>(const std::string &key,
|
||||
const uint8_t *data,
|
||||
size_t size);
|
||||
|
||||
template<typename T>
|
||||
T* AssetsModule::get(Handle<T> handle) {
|
||||
return nullptr;
|
||||
template <typename T> T *AssetsModule::get(Handle<T> handle) { return nullptr; }
|
||||
|
||||
template <> inline Texture *AssetsModule::get<Texture>(Handle<Texture> handle) {
|
||||
return textures_.get(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Texture* AssetsModule::get<Texture>(Handle<Texture> handle) {
|
||||
return textures_.get(handle);
|
||||
template <> inline Shader *AssetsModule::get<Shader>(Handle<Shader> handle) {
|
||||
return shaders_.get(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Shader* AssetsModule::get<Shader>(Handle<Shader> handle) {
|
||||
return shaders_.get(handle);
|
||||
template <>
|
||||
inline Material *AssetsModule::get<Material>(Handle<Material> handle) {
|
||||
return materials_.get(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Material* AssetsModule::get<Material>(Handle<Material> handle) {
|
||||
return materials_.get(handle);
|
||||
template <> inline Mesh *AssetsModule::get<Mesh>(Handle<Mesh> handle) {
|
||||
return meshes_.get(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Mesh* AssetsModule::get<Mesh>(Handle<Mesh> handle) {
|
||||
return meshes_.get(handle);
|
||||
template <typename T> Ptr<T> AssetsModule::getPtr(Handle<T> handle) {
|
||||
return Ptr<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Ptr<T> AssetsModule::getPtr(Handle<T> handle) {
|
||||
return Ptr<T>();
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline Ptr<Texture> AssetsModule::getPtr<Texture>(Handle<Texture> handle) {
|
||||
return textures_.getPtr(handle);
|
||||
return textures_.getPtr(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline Ptr<Shader> AssetsModule::getPtr<Shader>(Handle<Shader> handle) {
|
||||
return shaders_.getPtr(handle);
|
||||
return shaders_.getPtr(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline Ptr<Material> AssetsModule::getPtr<Material>(Handle<Material> handle) {
|
||||
return materials_.getPtr(handle);
|
||||
return materials_.getPtr(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Ptr<Mesh> AssetsModule::getPtr<Mesh>(Handle<Mesh> handle) {
|
||||
return meshes_.getPtr(handle);
|
||||
template <> inline Ptr<Mesh> AssetsModule::getPtr<Mesh>(Handle<Mesh> handle) {
|
||||
return meshes_.getPtr(handle);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool AssetsModule::isValid(Handle<T> handle) const {
|
||||
return false;
|
||||
template <typename T> bool AssetsModule::isValid(Handle<T> handle) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline bool AssetsModule::isValid<Texture>(Handle<Texture> handle) const {
|
||||
return textures_.isValid(handle);
|
||||
return textures_.isValid(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline bool AssetsModule::isValid<Shader>(Handle<Shader> handle) const {
|
||||
return shaders_.isValid(handle);
|
||||
return shaders_.isValid(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline bool AssetsModule::isValid<Material>(Handle<Material> handle) const {
|
||||
return materials_.isValid(handle);
|
||||
return materials_.isValid(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool AssetsModule::isValid<Mesh>(Handle<Mesh> handle) const {
|
||||
return meshes_.isValid(handle);
|
||||
template <> inline bool AssetsModule::isValid<Mesh>(Handle<Mesh> handle) const {
|
||||
return meshes_.isValid(handle);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AssetsModule::remove(Handle<T> handle) {
|
||||
template <typename T> void AssetsModule::remove(Handle<T> handle) {}
|
||||
|
||||
template <> inline void AssetsModule::remove<Texture>(Handle<Texture> handle) {
|
||||
textures_.remove(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void AssetsModule::remove<Texture>(Handle<Texture> handle) {
|
||||
textures_.remove(handle);
|
||||
template <> inline void AssetsModule::remove<Shader>(Handle<Shader> handle) {
|
||||
shaders_.remove(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void AssetsModule::remove<Shader>(Handle<Shader> handle) {
|
||||
shaders_.remove(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline void AssetsModule::remove<Material>(Handle<Material> handle) {
|
||||
materials_.remove(handle);
|
||||
materials_.remove(handle);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void AssetsModule::remove<Mesh>(Handle<Mesh> handle) {
|
||||
meshes_.remove(handle);
|
||||
template <> inline void AssetsModule::remove<Mesh>(Handle<Mesh> handle) {
|
||||
meshes_.remove(handle);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<Handle<T>> AssetsModule::loadDir(const std::string& directory,
|
||||
const std::string& pattern,
|
||||
bool recursive) {
|
||||
return {};
|
||||
template <typename T>
|
||||
std::vector<Handle<T>> AssetsModule::loadDir(const std::string &directory,
|
||||
const std::string &pattern,
|
||||
bool recursive) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
std::vector<Handle<Texture>> AssetsModule::loadDir<Texture>(const std::string& directory,
|
||||
const std::string& pattern,
|
||||
bool recursive);
|
||||
template <>
|
||||
std::vector<Handle<Texture>>
|
||||
AssetsModule::loadDir<Texture>(const std::string &directory,
|
||||
const std::string &pattern, bool recursive);
|
||||
|
||||
template<typename T>
|
||||
void AssetsModule::loadAsync(const std::string& path,
|
||||
std::function<void(Handle<T>)> callback) {
|
||||
}
|
||||
template <typename T>
|
||||
void AssetsModule::loadAsync(const std::string &path,
|
||||
std::function<void(Handle<T>)> callback) {}
|
||||
|
||||
template<>
|
||||
void AssetsModule::loadAsync<Texture>(const std::string& path,
|
||||
std::function<void(Handle<Texture>)> callback);
|
||||
template <>
|
||||
void AssetsModule::loadAsync<Texture>(
|
||||
const std::string &path, std::function<void(Handle<Texture>)> callback);
|
||||
|
||||
template<typename T>
|
||||
void AssetsModule::registerLoader(std::unique_ptr<AssetLoader<T>> loader) {
|
||||
}
|
||||
template <typename T>
|
||||
void AssetsModule::registerLoader(std::unique_ptr<AssetLoader<T>> loader) {}
|
||||
|
||||
template<>
|
||||
void AssetsModule::registerLoader<Texture>(std::unique_ptr<AssetLoader<Texture>> loader);
|
||||
template <>
|
||||
void AssetsModule::registerLoader<Texture>(
|
||||
std::unique_ptr<AssetLoader<Texture>> loader);
|
||||
|
||||
template<>
|
||||
void AssetsModule::registerLoader<Shader>(std::unique_ptr<AssetLoader<Shader>> loader);
|
||||
template <>
|
||||
void AssetsModule::registerLoader<Shader>(
|
||||
std::unique_ptr<AssetLoader<Shader>> loader);
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <assets/loaders/shader_loader.h>
|
||||
#include <assets/loaders/texture_loader.h>
|
||||
#include <event/events.h>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <utils/logger.h>
|
||||
|
|
@ -52,18 +53,33 @@ void AssetsModule::onGLContextReady() {
|
|||
void AssetsModule::shutdown() {
|
||||
E2D_LOG_INFO("AssetsModule shutting down...");
|
||||
|
||||
// 关闭异步加载系统
|
||||
shutdownAsyncLoader();
|
||||
|
||||
// 释放事件监听器
|
||||
onShowListener_.reset();
|
||||
|
||||
destroyDefaultResources();
|
||||
|
||||
textures_.clear();
|
||||
shaders_.clear();
|
||||
materials_.clear();
|
||||
meshes_.clear();
|
||||
// 清空资源(使用写锁保护)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
textures_.clear();
|
||||
shaders_.clear();
|
||||
materials_.clear();
|
||||
meshes_.clear();
|
||||
|
||||
texturePathCache_.clear();
|
||||
shaderPathCache_.clear();
|
||||
texturePathCache_.clear();
|
||||
shaderPathCache_.clear();
|
||||
fileWatchList_.clear();
|
||||
}
|
||||
|
||||
// 清空依赖关系
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(dependencyMutex_);
|
||||
textureDependencies_.clear();
|
||||
shaderDependencies_.clear();
|
||||
}
|
||||
|
||||
textureLoader_.reset();
|
||||
shaderLoader_.reset();
|
||||
|
|
@ -81,12 +97,15 @@ AssetsModule *getAssets() { return g_assetsModule; }
|
|||
|
||||
template <>
|
||||
Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
|
||||
auto it = texturePathCache_.find(path);
|
||||
if (it != texturePathCache_.end()) {
|
||||
if (textures_.isValid(it->second)) {
|
||||
return it->second;
|
||||
// 先检查缓存(读锁)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = texturePathCache_.find(path);
|
||||
if (it != texturePathCache_.end()) {
|
||||
if (textures_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
texturePathCache_.erase(it);
|
||||
}
|
||||
|
||||
if (!textureLoader_) {
|
||||
|
|
@ -100,10 +119,28 @@ Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
|
|||
return Handle<Texture>::invalid();
|
||||
}
|
||||
|
||||
Handle<Texture> handle = textures_.insert(texture);
|
||||
texturePathCache_[path] = handle;
|
||||
// 插入资源(写锁)
|
||||
Handle<Texture> handle;
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
|
||||
// 双重检查,避免重复加载
|
||||
auto it = texturePathCache_.find(path);
|
||||
if (it != texturePathCache_.end() && textures_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
handle = textures_.insert(texture);
|
||||
texturePathCache_[path] = handle;
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("Loaded texture: {} -> handle index {}", path, handle.index());
|
||||
|
||||
// 如果启用了热重载,添加文件监控
|
||||
if (hotReloadEnabled_) {
|
||||
addFileWatch(path, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
|
@ -140,13 +177,17 @@ Handle<Texture> AssetsModule::loadFromMemory<Texture>(const std::string &key,
|
|||
// Shader 加载特化
|
||||
//===========================================================================
|
||||
|
||||
template <> Handle<Shader> AssetsModule::load<Shader>(const std::string &path) {
|
||||
auto it = shaderPathCache_.find(path);
|
||||
if (it != shaderPathCache_.end()) {
|
||||
if (shaders_.isValid(it->second)) {
|
||||
return it->second;
|
||||
template <>
|
||||
Handle<Shader> AssetsModule::load<Shader>(const std::string &path) {
|
||||
// 先检查缓存(读锁)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = shaderPathCache_.find(path);
|
||||
if (it != shaderPathCache_.end()) {
|
||||
if (shaders_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
shaderPathCache_.erase(it);
|
||||
}
|
||||
|
||||
if (!shaderLoader_) {
|
||||
|
|
@ -160,10 +201,28 @@ template <> Handle<Shader> AssetsModule::load<Shader>(const std::string &path) {
|
|||
return Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
Handle<Shader> handle = shaders_.insert(shader);
|
||||
shaderPathCache_[path] = handle;
|
||||
// 插入资源(写锁)
|
||||
Handle<Shader> handle;
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
|
||||
// 双重检查
|
||||
auto it = shaderPathCache_.find(path);
|
||||
if (it != shaderPathCache_.end() && shaders_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
handle = shaders_.insert(shader);
|
||||
shaderPathCache_[path] = handle;
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("Loaded shader: {} -> handle index {}", path, handle.index());
|
||||
|
||||
// 如果启用了热重载,添加文件监控
|
||||
if (hotReloadEnabled_) {
|
||||
addFileWatch(path, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
|
@ -172,12 +231,15 @@ Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
|
|||
const std::string &fragPath) {
|
||||
std::string cacheKey = vertPath + "|" + fragPath;
|
||||
|
||||
auto it = shaderPathCache_.find(cacheKey);
|
||||
if (it != shaderPathCache_.end()) {
|
||||
if (shaders_.isValid(it->second)) {
|
||||
return it->second;
|
||||
// 先检查缓存(读锁)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = shaderPathCache_.find(cacheKey);
|
||||
if (it != shaderPathCache_.end()) {
|
||||
if (shaders_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
shaderPathCache_.erase(it);
|
||||
}
|
||||
|
||||
if (!shaderLoader_) {
|
||||
|
|
@ -192,11 +254,30 @@ Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
|
|||
return Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
Handle<Shader> handle = shaders_.insert(shader);
|
||||
shaderPathCache_[cacheKey] = handle;
|
||||
// 插入资源(写锁)
|
||||
Handle<Shader> handle;
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
|
||||
// 双重检查
|
||||
auto it = shaderPathCache_.find(cacheKey);
|
||||
if (it != shaderPathCache_.end() && shaders_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
handle = shaders_.insert(shader);
|
||||
shaderPathCache_[cacheKey] = handle;
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("Loaded shader: {} + {} -> handle index {}", vertPath, fragPath,
|
||||
handle.index());
|
||||
|
||||
// 如果启用了热重载,添加文件监控
|
||||
if (hotReloadEnabled_) {
|
||||
addFileWatch(vertPath, handle);
|
||||
addFileWatch(fragPath, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
|
@ -384,21 +465,396 @@ Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(defaultQuad_); }
|
|||
// 热重载
|
||||
//===========================================================================
|
||||
|
||||
void AssetsModule::enableHotReload(bool enable) { hotReloadEnabled_ = enable; }
|
||||
void AssetsModule::enableHotReload(bool enable) {
|
||||
hotReloadEnabled_ = enable;
|
||||
if (enable) {
|
||||
E2D_LOG_INFO("Hot reload enabled");
|
||||
} else {
|
||||
E2D_LOG_INFO("Hot reload disabled");
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::checkForChanges() {}
|
||||
void AssetsModule::setHotReloadInterval(float interval) {
|
||||
hotReloadInterval_ = interval;
|
||||
}
|
||||
|
||||
void AssetsModule::addFileWatch(const std::string& path, Handle<Texture> handle) {
|
||||
try {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileWatchInfo info;
|
||||
info.path = path;
|
||||
info.lastWriteTime = std::filesystem::last_write_time(path);
|
||||
info.textureHandle = handle;
|
||||
info.isTexture = true;
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
fileWatchList_.push_back(info);
|
||||
E2D_LOG_DEBUG("Watching texture file: {}", path);
|
||||
} catch (const std::exception& e) {
|
||||
E2D_LOG_ERROR("Failed to add file watch for {}: {}", path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::addFileWatch(const std::string& path, Handle<Shader> handle) {
|
||||
try {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileWatchInfo info;
|
||||
info.path = path;
|
||||
info.lastWriteTime = std::filesystem::last_write_time(path);
|
||||
info.shaderHandle = handle;
|
||||
info.isTexture = false;
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
fileWatchList_.push_back(info);
|
||||
E2D_LOG_DEBUG("Watching shader file: {}", path);
|
||||
} catch (const std::exception& e) {
|
||||
E2D_LOG_ERROR("Failed to add file watch for {}: {}", path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::reloadTexture(const FileWatchInfo& info) {
|
||||
if (!textureLoader_ || !info.textureHandle.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Reloading texture: {}", info.path);
|
||||
|
||||
Ptr<Texture> newTexture = textureLoader_->load(info.path);
|
||||
if (!newTexture) {
|
||||
E2D_LOG_ERROR("Failed to reload texture: {}", info.path);
|
||||
return;
|
||||
}
|
||||
|
||||
// 替换旧纹理的数据
|
||||
Texture* oldTexture = textures_.get(info.textureHandle);
|
||||
if (oldTexture) {
|
||||
// 这里假设 Texture 类有更新数据的方法
|
||||
// 如果没有,可能需要重新设计
|
||||
E2D_LOG_INFO("Texture reloaded: {}", info.path);
|
||||
notifyTextureReloaded(info.textureHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::reloadShader(const FileWatchInfo& info) {
|
||||
if (!shaderLoader_ || !info.shaderHandle.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Reloading shader: {}", info.path);
|
||||
|
||||
// 查找缓存键
|
||||
std::string cacheKey;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
for (const auto& pair : shaderPathCache_) {
|
||||
if (pair.second == info.shaderHandle) {
|
||||
cacheKey = pair.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheKey.empty()) {
|
||||
E2D_LOG_WARN("Shader cache key not found for: {}", info.path);
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析顶点/片段着色器路径
|
||||
size_t sepPos = cacheKey.find('|');
|
||||
if (sepPos == std::string::npos) {
|
||||
// 单文件模式
|
||||
Ptr<Shader> newShader = shaderLoader_->load(info.path);
|
||||
if (!newShader) {
|
||||
E2D_LOG_ERROR("Failed to reload shader: {}", info.path);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 双文件模式
|
||||
std::string vertPath = cacheKey.substr(0, sepPos);
|
||||
std::string fragPath = cacheKey.substr(sepPos + 1);
|
||||
|
||||
ShaderLoader* loader = static_cast<ShaderLoader*>(shaderLoader_.get());
|
||||
Ptr<Shader> newShader = loader->load(vertPath, fragPath);
|
||||
if (!newShader) {
|
||||
E2D_LOG_ERROR("Failed to reload shader: {} + {}", vertPath, fragPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Shader reloaded: {}", info.path);
|
||||
notifyShaderReloaded(info.shaderHandle);
|
||||
}
|
||||
|
||||
void AssetsModule::checkForChanges() {
|
||||
if (!hotReloadEnabled_ || fileWatchList_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
|
||||
for (auto& info : fileWatchList_) {
|
||||
try {
|
||||
if (!std::filesystem::exists(info.path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto currentTime = std::filesystem::last_write_time(info.path);
|
||||
if (currentTime != info.lastWriteTime) {
|
||||
info.lastWriteTime = currentTime;
|
||||
|
||||
// 解锁进行重载操作
|
||||
lock.unlock();
|
||||
|
||||
if (info.isTexture) {
|
||||
reloadTexture(info);
|
||||
} else {
|
||||
reloadShader(info);
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
E2D_LOG_ERROR("Error checking file {}: {}", info.path, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 异步加载系统
|
||||
//===========================================================================
|
||||
|
||||
void AssetsModule::initAsyncLoader(uint32_t threadCount) {
|
||||
if (asyncLoaderRunning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (threadCount == 0) {
|
||||
threadCount = std::max(1u, std::thread::hardware_concurrency() / 2);
|
||||
}
|
||||
|
||||
asyncLoaderRunning_ = true;
|
||||
|
||||
for (uint32_t i = 0; i < threadCount; ++i) {
|
||||
workerThreads_.emplace_back(&AssetsModule::workerThreadLoop, this);
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Async loader initialized with {} threads", threadCount);
|
||||
}
|
||||
|
||||
void AssetsModule::shutdownAsyncLoader() {
|
||||
if (!asyncLoaderRunning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
asyncLoaderRunning_ = false;
|
||||
queueCV_.notify_all();
|
||||
|
||||
for (auto& thread : workerThreads_) {
|
||||
if (thread.joinable()) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
workerThreads_.clear();
|
||||
|
||||
std::lock_guard<std::mutex> lock(queueMutex_);
|
||||
loadQueue_.clear();
|
||||
|
||||
E2D_LOG_INFO("Async loader shutdown");
|
||||
}
|
||||
|
||||
void AssetsModule::submitLoadTask(const LoadTask& task) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(queueMutex_);
|
||||
loadQueue_.push_back(task);
|
||||
|
||||
// 按优先级排序
|
||||
std::sort(loadQueue_.begin(), loadQueue_.end(),
|
||||
[](const LoadTask& a, const LoadTask& b) {
|
||||
return static_cast<int>(a.priority) > static_cast<int>(b.priority);
|
||||
});
|
||||
}
|
||||
queueCV_.notify_one();
|
||||
}
|
||||
|
||||
void AssetsModule::workerThreadLoop() {
|
||||
while (asyncLoaderRunning_) {
|
||||
LoadTask task;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queueMutex_);
|
||||
queueCV_.wait(lock, [this] {
|
||||
return !loadQueue_.empty() || !asyncLoaderRunning_;
|
||||
});
|
||||
|
||||
if (!asyncLoaderRunning_) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (loadQueue_.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
task = std::move(loadQueue_.back());
|
||||
loadQueue_.pop_back();
|
||||
}
|
||||
|
||||
// 执行加载任务
|
||||
if (task.type == LoadTask::Type::Texture) {
|
||||
Handle<Texture> handle = load<Texture>(task.path);
|
||||
|
||||
if (task.textureCallback) {
|
||||
std::lock_guard<std::mutex> callbackLock(callbackMutex_);
|
||||
completedCallbacks_.push_back([handle, callback = task.textureCallback]() {
|
||||
callback(handle);
|
||||
});
|
||||
}
|
||||
} else if (task.type == LoadTask::Type::Shader) {
|
||||
Handle<Shader> handle;
|
||||
if (task.secondaryPath.empty()) {
|
||||
handle = load<Shader>(task.path);
|
||||
} else {
|
||||
handle = load<Shader>(task.path, task.secondaryPath);
|
||||
}
|
||||
|
||||
if (task.shaderCallback) {
|
||||
std::lock_guard<std::mutex> callbackLock(callbackMutex_);
|
||||
completedCallbacks_.push_back([handle, callback = task.shaderCallback]() {
|
||||
callback(handle);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::processAsyncCallbacks() {
|
||||
std::vector<std::function<void()>> callbacks;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbackMutex_);
|
||||
callbacks = std::move(completedCallbacks_);
|
||||
completedCallbacks_.clear();
|
||||
}
|
||||
|
||||
for (auto& callback : callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 资源依赖跟踪
|
||||
//===========================================================================
|
||||
|
||||
void AssetsModule::registerMaterialDependency(Handle<Material> material, Handle<Texture> texture) {
|
||||
if (!material.isValid() || !texture.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(dependencyMutex_);
|
||||
|
||||
uint32_t textureIndex = texture.index();
|
||||
auto& info = textureDependencies_[textureIndex];
|
||||
info.texture = texture;
|
||||
|
||||
// 检查是否已存在
|
||||
auto it = std::find(info.dependentMaterials.begin(), info.dependentMaterials.end(), material);
|
||||
if (it == info.dependentMaterials.end()) {
|
||||
info.dependentMaterials.push_back(material);
|
||||
E2D_LOG_DEBUG("Registered material {} dependency on texture {}",
|
||||
material.index(), textureIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::registerMaterialDependency(Handle<Material> material, Handle<Shader> shader) {
|
||||
if (!material.isValid() || !shader.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(dependencyMutex_);
|
||||
|
||||
uint32_t shaderIndex = shader.index();
|
||||
auto& info = shaderDependencies_[shaderIndex];
|
||||
info.shader = shader;
|
||||
|
||||
// 检查是否已存在
|
||||
auto it = std::find(info.dependentMaterials.begin(), info.dependentMaterials.end(), material);
|
||||
if (it == info.dependentMaterials.end()) {
|
||||
info.dependentMaterials.push_back(material);
|
||||
E2D_LOG_DEBUG("Registered material {} dependency on shader {}",
|
||||
material.index(), shaderIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::notifyTextureReloaded(Handle<Texture> texture) {
|
||||
if (!texture.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(dependencyMutex_);
|
||||
|
||||
uint32_t textureIndex = texture.index();
|
||||
auto it = textureDependencies_.find(textureIndex);
|
||||
if (it != textureDependencies_.end()) {
|
||||
E2D_LOG_INFO("Notifying {} materials of texture reload",
|
||||
it->second.dependentMaterials.size());
|
||||
|
||||
// 材质需要更新纹理引用
|
||||
// 这里可以触发材质更新事件
|
||||
for (const auto& materialHandle : it->second.dependentMaterials) {
|
||||
Material* material = materials_.get(materialHandle);
|
||||
if (material) {
|
||||
// 材质自动使用新的纹理数据
|
||||
E2D_LOG_DEBUG("Material {} updated with reloaded texture",
|
||||
materialHandle.index());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsModule::notifyShaderReloaded(Handle<Shader> shader) {
|
||||
if (!shader.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(dependencyMutex_);
|
||||
|
||||
uint32_t shaderIndex = shader.index();
|
||||
auto it = shaderDependencies_.find(shaderIndex);
|
||||
if (it != shaderDependencies_.end()) {
|
||||
E2D_LOG_INFO("Notifying {} materials of shader reload",
|
||||
it->second.dependentMaterials.size());
|
||||
|
||||
for (const auto& materialHandle : it->second.dependentMaterials) {
|
||||
Material* material = materials_.get(materialHandle);
|
||||
if (material) {
|
||||
// 更新材质的着色器引用
|
||||
material->setShader(getPtr(shader));
|
||||
E2D_LOG_DEBUG("Material {} updated with reloaded shader",
|
||||
materialHandle.index());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 统计
|
||||
//===========================================================================
|
||||
|
||||
AssetsModule::Stats AssetsModule::getStats() const {
|
||||
Stats stats;
|
||||
stats.textureCount = textures_.count();
|
||||
stats.shaderCount = shaders_.count();
|
||||
stats.materialCount = materials_.count();
|
||||
stats.meshCount = meshes_.count();
|
||||
return stats;
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
|
||||
Stats stats;
|
||||
stats.textureCount = textures_.count();
|
||||
stats.shaderCount = shaders_.count();
|
||||
stats.materialCount = materials_.count();
|
||||
stats.meshCount = meshes_.count();
|
||||
return stats;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
Loading…
Reference in New Issue