Extra2D/include/assets/assets_module.h

524 lines
14 KiB
C
Raw Normal View History

#pragma once
#include <assets/asset_loader.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>
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();
/**
* @brief
* @param interval 1.0
*/
void setHotReloadInterval(float interval);
private:
/**
* @brief
*/
struct FileWatchInfo {
std::string path;
std::filesystem::file_time_type lastWriteTime;
Handle<Texture> textureHandle;
Handle<Shader> shaderHandle;
bool isTexture = false;
};
/**
* @brief
*/
void addFileWatch(const std::string &path, Handle<Texture> handle);
void addFileWatch(const std::string &path, Handle<Shader> 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<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();
//===========================================================================
// 模板实现
//===========================================================================
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