Extra2D/include/assets/assets_module.h

400 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 <functional>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
/**
* @brief 资源管理模块(主流 ECS 风格)
*
* 设计参考 Bevy/Amethyst
* - AssetStorage: 密集存储资源
* - load<T>(): 统一加载接口
* - Handle<T>: 轻量级句柄
*/
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<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 获取资源(返回指针,可能为 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>
bool isValid(Handle<T> handle) const;
/**
* @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 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 创建默认资源
* @return 是否成功
*/
bool createDefaultResources();
/**
* @brief 销毁默认资源
*/
void destroyDefaultResources();
Handle<Texture> getDefaultTexture();
Handle<Shader> getDefaultShader();
Handle<Material> getDefaultMaterial();
Handle<Mesh> getDefaultQuad();
Texture* getDefaultTexturePtr();
Shader* getDefaultShaderPtr();
Material* getDefaultMaterialPtr();
Mesh* getDefaultQuadPtr();
//===========================================================================
// 热重载
//===========================================================================
/**
* @brief 启用/禁用热重载
* @param enable 是否启用
*/
void enableHotReload(bool enable);
/**
* @brief 检查文件变更并重新加载
*/
void checkForChanges();
//===========================================================================
// 统计
//===========================================================================
struct Stats {
size_t textureCount = 0;
size_t shaderCount = 0;
size_t materialCount = 0;
size_t meshCount = 0;
};
Stats getStats() const;
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;
// 线程安全
mutable std::mutex mutex_;
// 事件监听器
std::unique_ptr<events::OnShow::Listener> onShowListener_;
// 标记默认资源是否已创建
bool defaultResourcesCreated_ = false;
};
// 全局访问
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<>
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& 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<>
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<>
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 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<typename T>
Ptr<T> AssetsModule::getPtr(Handle<T> handle) {
return Ptr<T>();
}
template<>
inline Ptr<Texture> AssetsModule::getPtr<Texture>(Handle<Texture> handle) {
return textures_.getPtr(handle);
}
template<>
inline Ptr<Shader> AssetsModule::getPtr<Shader>(Handle<Shader> handle) {
return shaders_.getPtr(handle);
}
template<>
inline Ptr<Material> AssetsModule::getPtr<Material>(Handle<Material> handle) {
return materials_.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<>
inline bool AssetsModule::isValid<Texture>(Handle<Texture> handle) const {
return textures_.isValid(handle);
}
template<>
inline bool AssetsModule::isValid<Shader>(Handle<Shader> handle) const {
return shaders_.isValid(handle);
}
template<>
inline bool AssetsModule::isValid<Material>(Handle<Material> handle) const {
return materials_.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<>
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<Material>(Handle<Material> handle) {
materials_.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<>
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<>
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<>
void AssetsModule::registerLoader<Texture>(std::unique_ptr<AssetLoader<Texture>> loader);
template<>
void AssetsModule::registerLoader<Shader>(std::unique_ptr<AssetLoader<Shader>> loader);
} // namespace extra2d