400 lines
11 KiB
C
400 lines
11 KiB
C
|
|
#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
|