refactor(assets): 重构资源系统架构,提取核心逻辑到 AssetSystem
- 新增 AssetSystem 类,整合异步加载、热重载、依赖跟踪等核心功能 - 将 AssetAsyncRuntime、AssetHotReloadRuntime 等组件提取为独立运行时类 - 重命名 AssetDependencyTracker 为 AssetDependencyGraph,改进数据结构 - 新增 BuiltinAssetFactory 负责默认资源的创建与管理 - 新增 AssetCache 提供线程安全的资源缓存机制 - 简化 AssetsModule 实现,将其职责委托给 AssetSystem - 保持原有 API 兼容性,仅重构内部实现
This commit is contained in:
parent
41817c9e8a
commit
b672b16b83
|
|
@ -1,10 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/asset_storage.h>
|
||||
#include <assets/async/asset_async_loader.h>
|
||||
#include <assets/deps/asset_dependency_tracker.h>
|
||||
#include <assets/hot_reload/asset_hot_reloader.h>
|
||||
#include <assets/io/asset_file_system.h>
|
||||
#include <assets/core/asset_system.h>
|
||||
#include <assets/asset_loader.h>
|
||||
#include <assets/handle.h>
|
||||
#include <atomic>
|
||||
|
|
@ -239,17 +236,6 @@ public:
|
|||
*/
|
||||
void setHotReloadInterval(float interval);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 重新加载纹理
|
||||
*/
|
||||
void reloadTexture(const AssetHotReloader::FileWatchInfo &info);
|
||||
|
||||
/**
|
||||
* @brief 重新加载着色器
|
||||
*/
|
||||
void reloadShader(const AssetHotReloader::FileWatchInfo &info);
|
||||
|
||||
public:
|
||||
//===========================================================================
|
||||
// 统计
|
||||
|
|
@ -285,9 +271,6 @@ private:
|
|||
Handle<Material> defaultMaterial_;
|
||||
Handle<Mesh> defaultQuad_;
|
||||
|
||||
AssetFileSystem fileSystem_;
|
||||
AssetHotReloader hotReloader_;
|
||||
|
||||
// 线程安全
|
||||
mutable std::shared_mutex mutex_;
|
||||
|
||||
|
|
@ -334,9 +317,6 @@ public:
|
|||
*/
|
||||
void processAsyncCallbacks();
|
||||
|
||||
private:
|
||||
AssetAsyncLoader asyncLoader_;
|
||||
|
||||
//===========================================================================
|
||||
// 资源依赖跟踪
|
||||
//===========================================================================
|
||||
|
|
@ -373,7 +353,7 @@ public:
|
|||
void notifyShaderReloaded(Handle<Shader> shader);
|
||||
|
||||
private:
|
||||
AssetDependencyTracker dependencyTracker_;
|
||||
std::unique_ptr<AssetSystem> system_;
|
||||
};
|
||||
|
||||
// 全局访问
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/asset_storage.h>
|
||||
#include <assets/handle.h>
|
||||
#include <assets/io/asset_file_system.h>
|
||||
#include <renderer/material.h>
|
||||
#include <renderer/mesh.h>
|
||||
#include <renderer/shader.h>
|
||||
#include <renderer/texture.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class BuiltinAssetFactory {
|
||||
public:
|
||||
BuiltinAssetFactory(AssetStorage<Texture> &textures, AssetStorage<Shader> &shaders,
|
||||
AssetStorage<Material> &materials, AssetStorage<Mesh> &meshes,
|
||||
const AssetFileSystem &fileSystem);
|
||||
|
||||
bool create();
|
||||
void destroy();
|
||||
|
||||
Handle<Texture> defaultTexture() const;
|
||||
Handle<Shader> defaultShader() const;
|
||||
Handle<Material> defaultMaterial() const;
|
||||
Handle<Mesh> defaultQuad() const;
|
||||
|
||||
private:
|
||||
AssetStorage<Texture> &textures_;
|
||||
AssetStorage<Shader> &shaders_;
|
||||
AssetStorage<Material> &materials_;
|
||||
AssetStorage<Mesh> &meshes_;
|
||||
const AssetFileSystem &fileSystem_;
|
||||
|
||||
Handle<Texture> defaultTexture_;
|
||||
Handle<Shader> defaultShader_;
|
||||
Handle<Material> defaultMaterial_;
|
||||
Handle<Mesh> defaultQuad_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/handle.h>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
template <typename T> class AssetCache {
|
||||
public:
|
||||
Handle<T> find(const std::string &key) const {
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = map_.find(key);
|
||||
if (it == map_.end()) {
|
||||
return Handle<T>::invalid();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void set(const std::string &key, Handle<T> handle) {
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
map_[key] = handle;
|
||||
}
|
||||
|
||||
void erase(const std::string &key) {
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
map_.erase(key);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
map_.clear();
|
||||
}
|
||||
|
||||
std::string findKeyByHandle(Handle<T> handle) const {
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
for (const auto &pair : map_) {
|
||||
if (pair.second == handle) {
|
||||
return pair.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, Handle<T>> map_;
|
||||
mutable std::shared_mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/asset_loader.h>
|
||||
#include <assets/asset_storage.h>
|
||||
#include <assets/builtin/builtin_asset_factory.h>
|
||||
#include <assets/cache/asset_cache.h>
|
||||
#include <assets/dependency/asset_dependency_graph.h>
|
||||
#include <assets/io/asset_file_system.h>
|
||||
#include <assets/runtime/asset_async_runtime.h>
|
||||
#include <assets/runtime/asset_hot_reload_runtime.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class ShaderLoader;
|
||||
|
||||
class AssetSystem {
|
||||
public:
|
||||
struct Stats {
|
||||
size_t textureCount = 0;
|
||||
size_t shaderCount = 0;
|
||||
size_t materialCount = 0;
|
||||
size_t meshCount = 0;
|
||||
};
|
||||
|
||||
AssetSystem(AssetStorage<Texture> &textures, AssetStorage<Shader> &shaders,
|
||||
AssetStorage<Material> &materials, AssetStorage<Mesh> &meshes,
|
||||
std::unique_ptr<AssetLoader<Texture>> &textureLoader,
|
||||
std::unique_ptr<AssetLoader<Shader>> &shaderLoader);
|
||||
|
||||
Handle<Texture> loadTexture(const std::string &path);
|
||||
Handle<Texture> loadTextureFromMemory(const std::string &key,
|
||||
const uint8_t *data, size_t size);
|
||||
std::vector<Handle<Texture>>
|
||||
loadTextureDir(const std::string &directory, bool recursive);
|
||||
|
||||
Handle<Shader> loadShader(const std::string &path);
|
||||
Handle<Shader> loadShader(const std::string &vertPath,
|
||||
const std::string &fragPath);
|
||||
|
||||
void loadTextureAsync(const std::string &path,
|
||||
std::function<void(Handle<Texture>)> callback);
|
||||
void loadShaderAsync(const std::string &path,
|
||||
std::function<void(Handle<Shader>)> callback);
|
||||
void initAsync(uint32_t threadCount = 0);
|
||||
void shutdownAsync();
|
||||
void processAsyncCallbacks();
|
||||
|
||||
void registerTextureLoader(std::unique_ptr<AssetLoader<Texture>> loader);
|
||||
void registerShaderLoader(std::unique_ptr<AssetLoader<Shader>> loader);
|
||||
|
||||
bool createDefaults();
|
||||
void destroyDefaults();
|
||||
Handle<Texture> defaultTexture() const;
|
||||
Handle<Shader> defaultShader() const;
|
||||
Handle<Material> defaultMaterial() const;
|
||||
Handle<Mesh> defaultQuad() const;
|
||||
|
||||
void enableHotReload(bool enable);
|
||||
void setHotReloadInterval(float interval);
|
||||
void checkForChanges();
|
||||
|
||||
void registerDependency(Handle<Material> material, Handle<Texture> texture);
|
||||
void registerDependency(Handle<Material> material, Handle<Shader> shader);
|
||||
void notifyTextureReloaded(Handle<Texture> texture);
|
||||
void notifyShaderReloaded(Handle<Shader> shader);
|
||||
|
||||
void clear();
|
||||
Stats stats() const;
|
||||
|
||||
private:
|
||||
void reloadTexture(const AssetHotReloader::FileWatchInfo &info);
|
||||
void reloadShader(const AssetHotReloader::FileWatchInfo &info);
|
||||
|
||||
AssetStorage<Texture> &textures_;
|
||||
AssetStorage<Shader> &shaders_;
|
||||
AssetStorage<Material> &materials_;
|
||||
AssetStorage<Mesh> &meshes_;
|
||||
|
||||
std::unique_ptr<AssetLoader<Texture>> &textureLoader_;
|
||||
std::unique_ptr<AssetLoader<Shader>> &shaderLoader_;
|
||||
|
||||
AssetCache<Texture> textureCache_;
|
||||
AssetCache<Shader> shaderCache_;
|
||||
AssetDependencyGraph dependencyGraph_;
|
||||
AssetAsyncRuntime asyncRuntime_;
|
||||
AssetHotReloadRuntime hotReloadRuntime_;
|
||||
BuiltinAssetFactory builtinFactory_;
|
||||
AssetFileSystem fileSystem_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,30 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/handle.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <renderer/material.h>
|
||||
#include <renderer/shader.h>
|
||||
#include <renderer/texture.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class AssetDependencyTracker {
|
||||
class AssetDependencyGraph {
|
||||
public:
|
||||
struct DependencyInfo {
|
||||
Handle<Texture> texture;
|
||||
Handle<Shader> shader;
|
||||
std::vector<Handle<Material>> dependentMaterials;
|
||||
};
|
||||
|
||||
void clear();
|
||||
void registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Texture> texture);
|
||||
void registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Shader> shader);
|
||||
void registerDependency(Handle<Material> material, Handle<Texture> texture);
|
||||
void registerDependency(Handle<Material> material, Handle<Shader> shader);
|
||||
void notifyTextureReloaded(
|
||||
Handle<Texture> texture,
|
||||
const std::function<void(Handle<Material>)> &onMaterialUpdate) const;
|
||||
|
|
@ -33,8 +25,18 @@ public:
|
|||
const std::function<void(Handle<Material>)> &onMaterialUpdate) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32_t, DependencyInfo> textureDependencies_;
|
||||
std::unordered_map<uint32_t, DependencyInfo> shaderDependencies_;
|
||||
struct TextureDeps {
|
||||
Handle<Texture> texture;
|
||||
std::vector<Handle<Material>> materials;
|
||||
};
|
||||
|
||||
struct ShaderDeps {
|
||||
Handle<Shader> shader;
|
||||
std::vector<Handle<Material>> materials;
|
||||
};
|
||||
|
||||
std::unordered_map<uint32_t, TextureDeps> textureDeps_;
|
||||
std::unordered_map<uint32_t, ShaderDeps> shaderDeps_;
|
||||
mutable std::shared_mutex mutex_;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/async/asset_async_loader.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class AssetAsyncRuntime {
|
||||
public:
|
||||
void init(uint32_t threadCount = 0);
|
||||
void shutdown();
|
||||
bool running() const;
|
||||
void submit(const AssetAsyncLoader::Task &task);
|
||||
void processCallbacks();
|
||||
|
||||
private:
|
||||
AssetAsyncLoader loader_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/hot_reload/asset_hot_reloader.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class AssetHotReloadRuntime {
|
||||
public:
|
||||
explicit AssetHotReloadRuntime(const AssetFileSystem &fileSystem);
|
||||
void enable(bool enable);
|
||||
bool enabled() const;
|
||||
void setInterval(float interval);
|
||||
void addWatch(const std::string &path, Handle<Texture> handle);
|
||||
void addWatch(const std::string &path, Handle<Shader> handle);
|
||||
void clear();
|
||||
void check(const std::function<void(const AssetHotReloader::FileWatchInfo &)>
|
||||
&reloadTexture,
|
||||
const std::function<void(const AssetHotReloader::FileWatchInfo &)>
|
||||
&reloadShader);
|
||||
|
||||
private:
|
||||
AssetHotReloader reloader_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -1,17 +1,14 @@
|
|||
#include <algorithm>
|
||||
#include <assets/assets_module.h>
|
||||
#include <assets/loaders/shader_loader.h>
|
||||
#include <assets/loaders/texture_loader.h>
|
||||
#include <event/events.h>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <utils/logger.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
AssetsModule *g_assetsModule = nullptr;
|
||||
|
||||
AssetsModule::AssetsModule() : hotReloader_(fileSystem_) { g_assetsModule = this; }
|
||||
AssetsModule::AssetsModule() { g_assetsModule = this; }
|
||||
|
||||
AssetsModule::~AssetsModule() {
|
||||
if (g_assetsModule == this) {
|
||||
|
|
@ -21,712 +18,263 @@ AssetsModule::~AssetsModule() {
|
|||
|
||||
bool AssetsModule::init() {
|
||||
E2D_INFO("资源模块正在初始化...");
|
||||
|
||||
textureLoader_ = std::make_unique<TextureLoader>();
|
||||
shaderLoader_ = std::make_unique<ShaderLoader>(fileSystem_);
|
||||
|
||||
// 监听窗口显示事件,在 OpenGL 上下文创建完成后创建默认资源
|
||||
shaderLoader_ = std::make_unique<ShaderLoader>();
|
||||
system_ = std::make_unique<AssetSystem>(textures_, shaders_, materials_, meshes_,
|
||||
textureLoader_, shaderLoader_);
|
||||
onShowListener_ = std::make_unique<events::OnShow::Listener>();
|
||||
onShowListener_->bind([this]() { this->onGLContextReady(); });
|
||||
|
||||
E2D_INFO("资源模块初始化成功 (等待 GL 上下文)");
|
||||
E2D_INFO("资源模块初始化成功 (V2)");
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetsModule::onGLContextReady() {
|
||||
if (defaultResourcesCreated_) {
|
||||
return;
|
||||
}
|
||||
|
||||
E2D_INFO("OpenGL 上下文就绪,正在创建默认资源...");
|
||||
|
||||
if (!createDefaultResources()) {
|
||||
E2D_ERROR("创建默认资源失败");
|
||||
return;
|
||||
}
|
||||
|
||||
defaultResourcesCreated_ = true;
|
||||
E2D_INFO("默认资源创建成功");
|
||||
}
|
||||
|
||||
void AssetsModule::shutdown() {
|
||||
E2D_INFO("资源模块正在关闭...");
|
||||
|
||||
// 关闭异步加载系统
|
||||
shutdownAsyncLoader();
|
||||
|
||||
// 释放事件监听器
|
||||
onShowListener_.reset();
|
||||
|
||||
destroyDefaultResources();
|
||||
|
||||
// 清空资源(使用写锁保护)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
textures_.clear();
|
||||
shaders_.clear();
|
||||
materials_.clear();
|
||||
meshes_.clear();
|
||||
|
||||
texturePathCache_.clear();
|
||||
shaderPathCache_.clear();
|
||||
if (system_) {
|
||||
system_->clear();
|
||||
system_.reset();
|
||||
}
|
||||
|
||||
hotReloader_.clear();
|
||||
dependencyTracker_.clear();
|
||||
|
||||
textures_.clear();
|
||||
shaders_.clear();
|
||||
materials_.clear();
|
||||
meshes_.clear();
|
||||
textureLoader_.reset();
|
||||
shaderLoader_.reset();
|
||||
|
||||
defaultResourcesCreated_ = false;
|
||||
|
||||
E2D_INFO("资源模块关闭完成");
|
||||
}
|
||||
|
||||
void AssetsModule::onGLContextReady() {
|
||||
if (defaultResourcesCreated_ || !system_) {
|
||||
return;
|
||||
}
|
||||
if (!system_->createDefaults()) {
|
||||
E2D_ERROR("创建默认资源失败");
|
||||
return;
|
||||
}
|
||||
defaultResourcesCreated_ = true;
|
||||
}
|
||||
|
||||
AssetsModule *getAssets() { return g_assetsModule; }
|
||||
|
||||
//===========================================================================
|
||||
// Texture 加载特化
|
||||
//===========================================================================
|
||||
|
||||
template <>
|
||||
Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
|
||||
// 先检查缓存(读锁)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!textureLoader_) {
|
||||
E2D_ERROR("纹理加载器未注册");
|
||||
template <> Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
|
||||
if (!system_) {
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
|
||||
Ptr<Texture> texture = textureLoader_->load(path);
|
||||
if (!texture) {
|
||||
E2D_ERROR("加载纹理失败: {}", path);
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
|
||||
// 插入资源(写锁)
|
||||
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_DEBUG("已加载纹理: {} -> 句柄索引 {}", path, handle.index());
|
||||
|
||||
// 如果启用了热重载,添加文件监控
|
||||
if (hotReloader_.enabled()) {
|
||||
hotReloader_.addFileWatch(path, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
return system_->loadTexture(path);
|
||||
}
|
||||
|
||||
template <>
|
||||
Handle<Texture> AssetsModule::loadFromMemory<Texture>(const std::string &key,
|
||||
const uint8_t *data,
|
||||
size_t size) {
|
||||
auto it = texturePathCache_.find(key);
|
||||
if (it != texturePathCache_.end()) {
|
||||
if (textures_.isValid(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
texturePathCache_.erase(it);
|
||||
}
|
||||
|
||||
if (!textureLoader_) {
|
||||
E2D_ERROR("纹理加载器未注册");
|
||||
if (!system_) {
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
|
||||
Ptr<Texture> texture = textureLoader_->loadFromMemory(data, size);
|
||||
if (!texture) {
|
||||
E2D_ERROR("从内存加载纹理失败: {}", key);
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
|
||||
Handle<Texture> handle = textures_.insert(texture);
|
||||
texturePathCache_[key] = handle;
|
||||
|
||||
return handle;
|
||||
return system_->loadTextureFromMemory(key, data, size);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Shader 加载特化
|
||||
//===========================================================================
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shaderLoader_) {
|
||||
E2D_ERROR("着色器加载器未注册");
|
||||
if (!system_) {
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
Ptr<Shader> shader = shaderLoader_->load(path);
|
||||
if (!shader) {
|
||||
E2D_ERROR("加载着色器失败: {}", path);
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
// 插入资源(写锁)
|
||||
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_DEBUG("已加载着色器: {} -> 句柄索引 {}", path, handle.index());
|
||||
|
||||
// 如果启用了热重载,添加文件监控
|
||||
if (hotReloader_.enabled()) {
|
||||
hotReloader_.addFileWatch(path, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
return system_->loadShader(path);
|
||||
}
|
||||
|
||||
template <>
|
||||
Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
|
||||
const std::string &fragPath) {
|
||||
std::string cacheKey = vertPath + "|" + fragPath;
|
||||
|
||||
// 先检查缓存(读锁)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shaderLoader_) {
|
||||
E2D_ERROR("着色器加载器未注册");
|
||||
if (!system_) {
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
ShaderLoader *shaderLoader = static_cast<ShaderLoader *>(shaderLoader_.get());
|
||||
Ptr<Shader> shader = shaderLoader->load(vertPath, fragPath);
|
||||
if (!shader) {
|
||||
E2D_ERROR("加载着色器失败: {} + {}", vertPath, fragPath);
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
// 插入资源(写锁)
|
||||
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_DEBUG("已加载着色器: {} + {} -> 句柄索引 {}", vertPath, fragPath,
|
||||
handle.index());
|
||||
|
||||
// 如果启用了热重载,添加文件监控
|
||||
if (hotReloader_.enabled()) {
|
||||
hotReloader_.addFileWatch(vertPath, handle);
|
||||
hotReloader_.addFileWatch(fragPath, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
return system_->loadShader(vertPath, fragPath);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 批量加载
|
||||
//===========================================================================
|
||||
|
||||
template <>
|
||||
std::vector<Handle<Texture>>
|
||||
AssetsModule::loadDir<Texture>(const std::string &directory,
|
||||
const std::string &pattern, bool recursive) {
|
||||
std::vector<Handle<Texture>> handles;
|
||||
|
||||
try {
|
||||
std::filesystem::path dirPath(directory);
|
||||
if (!fileSystem_.exists(directory)) {
|
||||
E2D_WARN("目录未找到: {}", directory);
|
||||
return handles;
|
||||
}
|
||||
|
||||
auto loadFile = [this, &handles](const std::filesystem::path &filePath) {
|
||||
std::string ext = filePath.extension().string();
|
||||
std::string pathStr = filePath.string();
|
||||
|
||||
for (const auto &supportedExt : textureLoader_->getExtensions()) {
|
||||
if (ext == supportedExt) {
|
||||
Handle<Texture> handle = load<Texture>(pathStr);
|
||||
if (handle.isValid()) {
|
||||
handles.push_back(handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (recursive) {
|
||||
for (const auto &entry :
|
||||
std::filesystem::recursive_directory_iterator(dirPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
loadFile(entry.path());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &entry : std::filesystem::directory_iterator(dirPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
loadFile(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
E2D_ERROR("加载目录 {} 时出错: {}", directory, e.what());
|
||||
(void)pattern;
|
||||
if (!system_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
E2D_DEBUG("已从 {} 加载 {} 个纹理", directory, handles.size());
|
||||
return handles;
|
||||
return system_->loadTextureDir(directory, recursive);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 异步加载
|
||||
//===========================================================================
|
||||
|
||||
template <>
|
||||
void AssetsModule::loadAsync<Texture>(
|
||||
const std::string &path, std::function<void(Handle<Texture>)> callback) {
|
||||
// 确保异步加载系统已初始化
|
||||
if (!asyncLoader_.isRunning()) {
|
||||
initAsyncLoader();
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建并提交加载任务
|
||||
LoadTask task;
|
||||
task.type = LoadTask::Type::Texture;
|
||||
task.priority = LoadTask::Priority::Normal;
|
||||
task.path = path;
|
||||
task.textureCallback = callback;
|
||||
|
||||
submitLoadTask(task);
|
||||
system_->loadTextureAsync(path, std::move(callback));
|
||||
}
|
||||
|
||||
template <>
|
||||
void AssetsModule::loadAsync<Shader>(
|
||||
const std::string &path, std::function<void(Handle<Shader>)> callback) {
|
||||
// 确保异步加载系统已初始化
|
||||
if (!asyncLoader_.isRunning()) {
|
||||
initAsyncLoader();
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建并提交加载任务
|
||||
LoadTask task;
|
||||
task.type = LoadTask::Type::Shader;
|
||||
task.priority = LoadTask::Priority::Normal;
|
||||
task.path = path;
|
||||
task.secondaryPath = "";
|
||||
task.shaderCallback = callback;
|
||||
|
||||
submitLoadTask(task);
|
||||
system_->loadShaderAsync(path, std::move(callback));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 加载器注册
|
||||
//===========================================================================
|
||||
|
||||
template <>
|
||||
void AssetsModule::registerLoader<Texture>(
|
||||
std::unique_ptr<AssetLoader<Texture>> loader) {
|
||||
textureLoader_ = std::move(loader);
|
||||
if (!system_) {
|
||||
textureLoader_ = std::move(loader);
|
||||
return;
|
||||
}
|
||||
system_->registerTextureLoader(std::move(loader));
|
||||
}
|
||||
|
||||
template <>
|
||||
void AssetsModule::registerLoader<Shader>(
|
||||
std::unique_ptr<AssetLoader<Shader>> loader) {
|
||||
shaderLoader_ = std::move(loader);
|
||||
if (!system_) {
|
||||
shaderLoader_ = std::move(loader);
|
||||
return;
|
||||
}
|
||||
system_->registerShaderLoader(std::move(loader));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 默认资源
|
||||
//===========================================================================
|
||||
|
||||
bool AssetsModule::createDefaultResources() {
|
||||
{
|
||||
Ptr<Texture> texture = makePtr<Texture>();
|
||||
uint8_t whitePixel[] = {255, 255, 255, 255};
|
||||
if (!texture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8)) {
|
||||
E2D_ERROR("创建默认纹理失败");
|
||||
return false;
|
||||
}
|
||||
defaultTexture_ = textures_.insert(texture);
|
||||
E2D_DEBUG("已创建默认纹理");
|
||||
if (!system_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// 从文件加载默认着色器
|
||||
// 使用 FileModule 的 assetPath 来获取正确的资源路径(支持 RomFS)
|
||||
std::string vertPath = fileSystem_.assetPath("shader/default.vert");
|
||||
std::string fragPath = fileSystem_.assetPath("shader/default.frag");
|
||||
|
||||
if (!fileSystem_.exists(vertPath) || !fileSystem_.exists(fragPath)) {
|
||||
E2D_ERROR("默认着色器文件未找到: {}, {}", vertPath, fragPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 读取着色器文件内容
|
||||
std::string vsSource = fileSystem_.readString(vertPath);
|
||||
std::string fsSource = fileSystem_.readString(fragPath);
|
||||
if (vsSource.empty() || fsSource.empty()) {
|
||||
E2D_ERROR("读取默认着色器文件失败: {}, {}", vertPath, fragPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从源码加载着色器
|
||||
Ptr<Shader> shader = makePtr<Shader>();
|
||||
if (!shader->loadFromSource(vsSource, fsSource)) {
|
||||
E2D_ERROR("编译默认着色器失败: {}, {}", vertPath, fragPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
defaultShader_ = shaders_.insert(shader);
|
||||
E2D_DEBUG("已从文件加载默认着色器: {}, {}", vertPath, fragPath);
|
||||
}
|
||||
|
||||
{
|
||||
// 创建材质布局(与着色器中的 MaterialUBO 匹配)
|
||||
// layout(std140, binding = 1) uniform MaterialUBO {
|
||||
// vec4 uColor; // 16 bytes
|
||||
// vec4 uTintColor; // 16 bytes
|
||||
// float uOpacity; // 4 bytes
|
||||
// float uPadding[3]; // 12 bytes
|
||||
// };
|
||||
Ptr<MaterialLayout> layout = makePtr<MaterialLayout>();
|
||||
layout->addParam("uColor", MaterialParamType::Color);
|
||||
layout->addParam("uTintColor", MaterialParamType::Color);
|
||||
layout->addParam("uOpacity", MaterialParamType::Float);
|
||||
layout->finalize();
|
||||
|
||||
Ptr<Material> material = makePtr<Material>();
|
||||
material->setShader(getPtr(defaultShader_));
|
||||
material->setLayout(layout);
|
||||
|
||||
// 设置默认材质参数
|
||||
material->setColor("uColor", Color::White);
|
||||
material->setColor("uTintColor", Color::White);
|
||||
material->setFloat("uOpacity", 1.0f);
|
||||
|
||||
// 添加默认纹理到材质
|
||||
material->setTexture("uTexture", getPtr(defaultTexture_), 0);
|
||||
defaultMaterial_ = materials_.insert(material);
|
||||
E2D_DEBUG("已创建默认材质,使用默认纹理和布局");
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<Mesh> mesh = Mesh::createQuad(Vec2(1.0f, 1.0f));
|
||||
if (!mesh) {
|
||||
E2D_ERROR("创建默认四边形网格失败");
|
||||
return false;
|
||||
}
|
||||
defaultQuad_ = meshes_.insert(mesh);
|
||||
E2D_DEBUG("已创建默认四边形网格");
|
||||
}
|
||||
|
||||
return true;
|
||||
return system_->createDefaults();
|
||||
}
|
||||
|
||||
void AssetsModule::destroyDefaultResources() {
|
||||
materials_.remove(defaultMaterial_);
|
||||
meshes_.remove(defaultQuad_);
|
||||
textures_.remove(defaultTexture_);
|
||||
shaders_.remove(defaultShader_);
|
||||
|
||||
defaultMaterial_ = Handle<Material>::invalid();
|
||||
defaultQuad_ = Handle<Mesh>::invalid();
|
||||
defaultTexture_ = Handle<Texture>::invalid();
|
||||
defaultShader_ = Handle<Shader>::invalid();
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->destroyDefaults();
|
||||
}
|
||||
|
||||
Handle<Texture> AssetsModule::getDefaultTexture() { return defaultTexture_; }
|
||||
|
||||
Handle<Shader> AssetsModule::getDefaultShader() { return defaultShader_; }
|
||||
|
||||
Handle<Material> AssetsModule::getDefaultMaterial() { return defaultMaterial_; }
|
||||
|
||||
Handle<Mesh> AssetsModule::getDefaultQuad() { return defaultQuad_; }
|
||||
|
||||
Texture *AssetsModule::getDefaultTexturePtr() {
|
||||
return textures_.get(defaultTexture_);
|
||||
Handle<Texture> AssetsModule::getDefaultTexture() {
|
||||
return system_ ? system_->defaultTexture() : Handle<Texture>::invalid();
|
||||
}
|
||||
|
||||
Shader *AssetsModule::getDefaultShaderPtr() {
|
||||
return shaders_.get(defaultShader_);
|
||||
Handle<Shader> AssetsModule::getDefaultShader() {
|
||||
return system_ ? system_->defaultShader() : Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
Handle<Material> AssetsModule::getDefaultMaterial() {
|
||||
return system_ ? system_->defaultMaterial() : Handle<Material>::invalid();
|
||||
}
|
||||
|
||||
Handle<Mesh> AssetsModule::getDefaultQuad() {
|
||||
return system_ ? system_->defaultQuad() : Handle<Mesh>::invalid();
|
||||
}
|
||||
|
||||
Texture *AssetsModule::getDefaultTexturePtr() { return textures_.get(getDefaultTexture()); }
|
||||
|
||||
Shader *AssetsModule::getDefaultShaderPtr() { return shaders_.get(getDefaultShader()); }
|
||||
|
||||
Material *AssetsModule::getDefaultMaterialPtr() {
|
||||
return materials_.get(defaultMaterial_);
|
||||
return materials_.get(getDefaultMaterial());
|
||||
}
|
||||
|
||||
Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(defaultQuad_); }
|
||||
|
||||
//===========================================================================
|
||||
// 热重载
|
||||
//===========================================================================
|
||||
Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(getDefaultQuad()); }
|
||||
|
||||
void AssetsModule::enableHotReload(bool enable) {
|
||||
hotReloader_.enable(enable);
|
||||
if (enable) {
|
||||
E2D_INFO("热重载已启用");
|
||||
} else {
|
||||
E2D_INFO("热重载已禁用");
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->enableHotReload(enable);
|
||||
}
|
||||
|
||||
void AssetsModule::setHotReloadInterval(float interval) {
|
||||
hotReloader_.setInterval(interval);
|
||||
}
|
||||
|
||||
void AssetsModule::reloadTexture(const AssetHotReloader::FileWatchInfo &info) {
|
||||
if (!textureLoader_ || !info.textureHandle.isValid()) {
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
|
||||
E2D_INFO("正在重载纹理: {}", info.path);
|
||||
|
||||
// 获取旧纹理指针
|
||||
Texture *oldTexture = textures_.get(info.textureHandle);
|
||||
if (!oldTexture) {
|
||||
E2D_ERROR("未找到要重载的旧纹理: {}", info.path);
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接在原有纹理对象上重新加载
|
||||
if (!oldTexture->reloadFromFile(info.path)) {
|
||||
E2D_ERROR("重载纹理失败: {}", info.path);
|
||||
return;
|
||||
}
|
||||
|
||||
E2D_INFO("纹理重载成功: {}", info.path);
|
||||
notifyTextureReloaded(info.textureHandle);
|
||||
}
|
||||
|
||||
void AssetsModule::reloadShader(const AssetHotReloader::FileWatchInfo &info) {
|
||||
if (!shaderLoader_ || !info.shaderHandle.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
E2D_INFO("正在重载着色器: {}", info.path);
|
||||
|
||||
// 获取旧着色器指针
|
||||
Shader *oldShader = shaders_.get(info.shaderHandle);
|
||||
if (!oldShader) {
|
||||
E2D_ERROR("未找到要重载的旧着色器: {}", info.path);
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找缓存键
|
||||
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_WARN("未找到着色器缓存键: {}", info.path);
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析顶点/片段着色器路径并重新加载
|
||||
size_t sepPos = cacheKey.find('|');
|
||||
if (sepPos == std::string::npos) {
|
||||
// 单文件模式 - 这里暂不支持,因为 ShaderLoader 目前只支持双文件
|
||||
E2D_WARN("不支持单文件着色器重载: {}", info.path);
|
||||
} else {
|
||||
// 双文件模式
|
||||
std::string vertPath = cacheKey.substr(0, sepPos);
|
||||
std::string fragPath = cacheKey.substr(sepPos + 1);
|
||||
|
||||
// 读取着色器文件内容
|
||||
std::string vsSource = fileSystem_.readString(vertPath);
|
||||
std::string fsSource = fileSystem_.readString(fragPath);
|
||||
if (vsSource.empty() || fsSource.empty()) {
|
||||
E2D_ERROR("读取着色器文件失败: {}, {}", vertPath, fragPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接在原有着色器对象上重新加载
|
||||
if (!oldShader->reloadFromSource(vsSource, fsSource)) {
|
||||
E2D_ERROR("重载着色器失败: {} + {}", vertPath, fragPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
E2D_INFO("着色器重载成功: {}", info.path);
|
||||
notifyShaderReloaded(info.shaderHandle);
|
||||
system_->setHotReloadInterval(interval);
|
||||
}
|
||||
|
||||
void AssetsModule::checkForChanges() {
|
||||
hotReloader_.checkForChanges(
|
||||
[this](const AssetHotReloader::FileWatchInfo &info) {
|
||||
reloadTexture(info);
|
||||
},
|
||||
[this](const AssetHotReloader::FileWatchInfo &info) {
|
||||
reloadShader(info);
|
||||
});
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 异步加载系统
|
||||
//===========================================================================
|
||||
|
||||
void AssetsModule::initAsyncLoader(uint32_t threadCount) {
|
||||
if (asyncLoader_.isRunning()) {
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
asyncLoader_.init(threadCount);
|
||||
E2D_INFO("异步加载器已初始化,使用 {} 个线程", threadCount);
|
||||
system_->checkForChanges();
|
||||
}
|
||||
|
||||
void AssetsModule::initAsyncLoader(uint32_t threadCount) {
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->initAsync(threadCount);
|
||||
}
|
||||
|
||||
void AssetsModule::shutdownAsyncLoader() {
|
||||
if (!asyncLoader_.isRunning()) {
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
asyncLoader_.shutdown();
|
||||
E2D_INFO("异步加载器已关闭");
|
||||
system_->shutdownAsync();
|
||||
}
|
||||
|
||||
void AssetsModule::submitLoadTask(const LoadTask &task) {
|
||||
AssetAsyncLoader::Task asyncTask;
|
||||
asyncTask.priority = static_cast<AssetAsyncLoader::Priority>(task.priority);
|
||||
|
||||
if (task.type == LoadTask::Type::Texture) {
|
||||
auto handle = std::make_shared<Handle<Texture>>(Handle<Texture>::invalid());
|
||||
asyncTask.work = [this, path = task.path, handle]() {
|
||||
*handle = load<Texture>(path);
|
||||
};
|
||||
if (task.textureCallback) {
|
||||
asyncTask.onComplete = [handle, callback = task.textureCallback]() {
|
||||
callback(*handle);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
auto handle = std::make_shared<Handle<Shader>>(Handle<Shader>::invalid());
|
||||
asyncTask.work = [this, path = task.path, secondary = task.secondaryPath,
|
||||
handle]() {
|
||||
if (secondary.empty()) {
|
||||
*handle = load<Shader>(path);
|
||||
} else {
|
||||
*handle = load<Shader>(path, secondary);
|
||||
}
|
||||
};
|
||||
if (task.shaderCallback) {
|
||||
asyncTask.onComplete = [handle, callback = task.shaderCallback]() {
|
||||
callback(*handle);
|
||||
};
|
||||
}
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
if (task.type == LoadTask::Type::Texture) {
|
||||
system_->loadTextureAsync(task.path, task.textureCallback);
|
||||
} else {
|
||||
system_->loadShaderAsync(task.path, task.shaderCallback);
|
||||
}
|
||||
|
||||
asyncLoader_.submit(asyncTask);
|
||||
}
|
||||
|
||||
void AssetsModule::processAsyncCallbacks() {
|
||||
asyncLoader_.processCallbacks();
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->processAsyncCallbacks();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 资源依赖跟踪
|
||||
//===========================================================================
|
||||
|
||||
void AssetsModule::registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Texture> texture) {
|
||||
dependencyTracker_.registerMaterialDependency(material, texture);
|
||||
E2D_DEBUG("已注册材质 {} 对纹理 {} 的依赖", material.index(), texture.index());
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->registerDependency(material, texture);
|
||||
}
|
||||
|
||||
void AssetsModule::registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Shader> shader) {
|
||||
dependencyTracker_.registerMaterialDependency(material, shader);
|
||||
E2D_DEBUG("已注册材质 {} 对着色器 {} 的依赖", material.index(),
|
||||
shader.index());
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->registerDependency(material, shader);
|
||||
}
|
||||
|
||||
void AssetsModule::notifyTextureReloaded(Handle<Texture> texture) {
|
||||
dependencyTracker_.notifyTextureReloaded(
|
||||
texture, [this](Handle<Material> materialHandle) {
|
||||
Material *material = materials_.get(materialHandle);
|
||||
if (material) {
|
||||
E2D_DEBUG("材质 {} 已更新为重载后的纹理", materialHandle.index());
|
||||
}
|
||||
});
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->notifyTextureReloaded(texture);
|
||||
}
|
||||
|
||||
void AssetsModule::notifyShaderReloaded(Handle<Shader> shader) {
|
||||
dependencyTracker_.notifyShaderReloaded(
|
||||
shader, [this, shader](Handle<Material> materialHandle) {
|
||||
Material *material = materials_.get(materialHandle);
|
||||
if (material) {
|
||||
material->setShader(getPtr(shader));
|
||||
E2D_DEBUG("材质 {} 已更新为重载后的着色器", materialHandle.index());
|
||||
}
|
||||
});
|
||||
if (!system_) {
|
||||
return;
|
||||
}
|
||||
system_->notifyShaderReloaded(shader);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// 统计
|
||||
//===========================================================================
|
||||
|
||||
AssetsModule::Stats AssetsModule::getStats() const {
|
||||
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();
|
||||
if (!system_) {
|
||||
return stats;
|
||||
}
|
||||
AssetSystem::Stats systemStats = system_->stats();
|
||||
stats.textureCount = systemStats.textureCount;
|
||||
stats.shaderCount = systemStats.shaderCount;
|
||||
stats.materialCount = systemStats.materialCount;
|
||||
stats.meshCount = systemStats.meshCount;
|
||||
return stats;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
#include <assets/builtin/builtin_asset_factory.h>
|
||||
#include <utils/logger.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
BuiltinAssetFactory::BuiltinAssetFactory(AssetStorage<Texture> &textures,
|
||||
AssetStorage<Shader> &shaders,
|
||||
AssetStorage<Material> &materials,
|
||||
AssetStorage<Mesh> &meshes,
|
||||
const AssetFileSystem &fileSystem)
|
||||
: textures_(textures), shaders_(shaders), materials_(materials), meshes_(meshes),
|
||||
fileSystem_(fileSystem) {}
|
||||
|
||||
bool BuiltinAssetFactory::create() {
|
||||
{
|
||||
Ptr<Texture> texture = makePtr<Texture>();
|
||||
uint8_t whitePixel[] = {255, 255, 255, 255};
|
||||
if (!texture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8)) {
|
||||
return false;
|
||||
}
|
||||
defaultTexture_ = textures_.insert(texture);
|
||||
}
|
||||
|
||||
{
|
||||
std::string vertPath = fileSystem_.assetPath("shader/default.vert");
|
||||
std::string fragPath = fileSystem_.assetPath("shader/default.frag");
|
||||
if (!fileSystem_.exists(vertPath) || !fileSystem_.exists(fragPath)) {
|
||||
return false;
|
||||
}
|
||||
std::string vsSource = fileSystem_.readString(vertPath);
|
||||
std::string fsSource = fileSystem_.readString(fragPath);
|
||||
if (vsSource.empty() || fsSource.empty()) {
|
||||
return false;
|
||||
}
|
||||
Ptr<Shader> shader = makePtr<Shader>();
|
||||
if (!shader->loadFromSource(vsSource, fsSource)) {
|
||||
return false;
|
||||
}
|
||||
defaultShader_ = shaders_.insert(shader);
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<MaterialLayout> layout = makePtr<MaterialLayout>();
|
||||
layout->addParam("uColor", MaterialParamType::Color);
|
||||
layout->addParam("uTintColor", MaterialParamType::Color);
|
||||
layout->addParam("uOpacity", MaterialParamType::Float);
|
||||
layout->finalize();
|
||||
|
||||
Ptr<Material> material = makePtr<Material>();
|
||||
material->setShader(shaders_.getPtr(defaultShader_));
|
||||
material->setLayout(layout);
|
||||
material->setColor("uColor", Color::White);
|
||||
material->setColor("uTintColor", Color::White);
|
||||
material->setFloat("uOpacity", 1.0f);
|
||||
material->setTexture("uTexture", textures_.getPtr(defaultTexture_), 0);
|
||||
defaultMaterial_ = materials_.insert(material);
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<Mesh> mesh = Mesh::createQuad(Vec2(1.0f, 1.0f));
|
||||
if (!mesh) {
|
||||
return false;
|
||||
}
|
||||
defaultQuad_ = meshes_.insert(mesh);
|
||||
}
|
||||
|
||||
E2D_DEBUG("BuiltinAssetFactory: 默认资源创建完成");
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuiltinAssetFactory::destroy() {
|
||||
materials_.remove(defaultMaterial_);
|
||||
meshes_.remove(defaultQuad_);
|
||||
textures_.remove(defaultTexture_);
|
||||
shaders_.remove(defaultShader_);
|
||||
defaultMaterial_ = Handle<Material>::invalid();
|
||||
defaultQuad_ = Handle<Mesh>::invalid();
|
||||
defaultTexture_ = Handle<Texture>::invalid();
|
||||
defaultShader_ = Handle<Shader>::invalid();
|
||||
}
|
||||
|
||||
Handle<Texture> BuiltinAssetFactory::defaultTexture() const {
|
||||
return defaultTexture_;
|
||||
}
|
||||
|
||||
Handle<Shader> BuiltinAssetFactory::defaultShader() const { return defaultShader_; }
|
||||
|
||||
Handle<Material> BuiltinAssetFactory::defaultMaterial() const {
|
||||
return defaultMaterial_;
|
||||
}
|
||||
|
||||
Handle<Mesh> BuiltinAssetFactory::defaultQuad() const { return defaultQuad_; }
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
#include <assets/core/asset_system.h>
|
||||
#include <assets/loaders/shader_loader.h>
|
||||
#include <filesystem>
|
||||
#include <utils/logger.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
AssetSystem::AssetSystem(AssetStorage<Texture> &textures,
|
||||
AssetStorage<Shader> &shaders,
|
||||
AssetStorage<Material> &materials,
|
||||
AssetStorage<Mesh> &meshes,
|
||||
std::unique_ptr<AssetLoader<Texture>> &textureLoader,
|
||||
std::unique_ptr<AssetLoader<Shader>> &shaderLoader)
|
||||
: textures_(textures), shaders_(shaders), materials_(materials), meshes_(meshes),
|
||||
textureLoader_(textureLoader), shaderLoader_(shaderLoader),
|
||||
hotReloadRuntime_(fileSystem_),
|
||||
builtinFactory_(textures, shaders, materials, meshes, fileSystem_) {}
|
||||
|
||||
Handle<Texture> AssetSystem::loadTexture(const std::string &path) {
|
||||
Handle<Texture> cached = textureCache_.find(path);
|
||||
if (cached.isValid() && textures_.isValid(cached)) {
|
||||
return cached;
|
||||
}
|
||||
if (!textureLoader_) {
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
Ptr<Texture> texture = textureLoader_->load(path);
|
||||
if (!texture) {
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
Handle<Texture> handle = textures_.insert(texture);
|
||||
textureCache_.set(path, handle);
|
||||
if (hotReloadRuntime_.enabled()) {
|
||||
hotReloadRuntime_.addWatch(path, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
Handle<Texture> AssetSystem::loadTextureFromMemory(const std::string &key,
|
||||
const uint8_t *data,
|
||||
size_t size) {
|
||||
Handle<Texture> cached = textureCache_.find(key);
|
||||
if (cached.isValid() && textures_.isValid(cached)) {
|
||||
return cached;
|
||||
}
|
||||
if (!textureLoader_) {
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
Ptr<Texture> texture = textureLoader_->loadFromMemory(data, size);
|
||||
if (!texture) {
|
||||
return Handle<Texture>::invalid();
|
||||
}
|
||||
Handle<Texture> handle = textures_.insert(texture);
|
||||
textureCache_.set(key, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
std::vector<Handle<Texture>>
|
||||
AssetSystem::loadTextureDir(const std::string &directory, bool recursive) {
|
||||
std::vector<Handle<Texture>> handles;
|
||||
if (!textureLoader_ || !fileSystem_.exists(directory)) {
|
||||
return handles;
|
||||
}
|
||||
std::filesystem::path dirPath(directory);
|
||||
auto loadFile = [this, &handles](const std::filesystem::path &filePath) {
|
||||
std::string ext = filePath.extension().string();
|
||||
for (const auto &supported : textureLoader_->getExtensions()) {
|
||||
if (ext == supported) {
|
||||
Handle<Texture> handle = loadTexture(filePath.string());
|
||||
if (handle.isValid()) {
|
||||
handles.push_back(handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
if (recursive) {
|
||||
for (const auto &entry :
|
||||
std::filesystem::recursive_directory_iterator(dirPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
loadFile(entry.path());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &entry : std::filesystem::directory_iterator(dirPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
loadFile(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
return {};
|
||||
}
|
||||
return handles;
|
||||
}
|
||||
|
||||
Handle<Shader> AssetSystem::loadShader(const std::string &path) {
|
||||
Handle<Shader> cached = shaderCache_.find(path);
|
||||
if (cached.isValid() && shaders_.isValid(cached)) {
|
||||
return cached;
|
||||
}
|
||||
if (!shaderLoader_) {
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
Ptr<Shader> shader = shaderLoader_->load(path);
|
||||
if (!shader) {
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
Handle<Shader> handle = shaders_.insert(shader);
|
||||
shaderCache_.set(path, handle);
|
||||
if (hotReloadRuntime_.enabled()) {
|
||||
hotReloadRuntime_.addWatch(path, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
Handle<Shader> AssetSystem::loadShader(const std::string &vertPath,
|
||||
const std::string &fragPath) {
|
||||
std::string key = vertPath + "|" + fragPath;
|
||||
Handle<Shader> cached = shaderCache_.find(key);
|
||||
if (cached.isValid() && shaders_.isValid(cached)) {
|
||||
return cached;
|
||||
}
|
||||
if (!shaderLoader_) {
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
ShaderLoader *shaderLoader = static_cast<ShaderLoader *>(shaderLoader_.get());
|
||||
Ptr<Shader> shader = shaderLoader->load(vertPath, fragPath);
|
||||
if (!shader) {
|
||||
return Handle<Shader>::invalid();
|
||||
}
|
||||
Handle<Shader> handle = shaders_.insert(shader);
|
||||
shaderCache_.set(key, handle);
|
||||
if (hotReloadRuntime_.enabled()) {
|
||||
hotReloadRuntime_.addWatch(vertPath, handle);
|
||||
hotReloadRuntime_.addWatch(fragPath, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void AssetSystem::initAsync(uint32_t threadCount) {
|
||||
if (asyncRuntime_.running()) {
|
||||
return;
|
||||
}
|
||||
asyncRuntime_.init(threadCount);
|
||||
}
|
||||
|
||||
void AssetSystem::shutdownAsync() {
|
||||
if (!asyncRuntime_.running()) {
|
||||
return;
|
||||
}
|
||||
asyncRuntime_.shutdown();
|
||||
}
|
||||
|
||||
void AssetSystem::loadTextureAsync(
|
||||
const std::string &path, std::function<void(Handle<Texture>)> callback) {
|
||||
if (!asyncRuntime_.running()) {
|
||||
initAsync();
|
||||
}
|
||||
auto handle = std::make_shared<Handle<Texture>>(Handle<Texture>::invalid());
|
||||
AssetAsyncLoader::Task task;
|
||||
task.priority = AssetAsyncLoader::Priority::Normal;
|
||||
task.work = [this, path, handle]() { *handle = loadTexture(path); };
|
||||
task.onComplete = [handle, callback]() {
|
||||
if (callback) {
|
||||
callback(*handle);
|
||||
}
|
||||
};
|
||||
asyncRuntime_.submit(task);
|
||||
}
|
||||
|
||||
void AssetSystem::loadShaderAsync(
|
||||
const std::string &path, std::function<void(Handle<Shader>)> callback) {
|
||||
if (!asyncRuntime_.running()) {
|
||||
initAsync();
|
||||
}
|
||||
auto handle = std::make_shared<Handle<Shader>>(Handle<Shader>::invalid());
|
||||
AssetAsyncLoader::Task task;
|
||||
task.priority = AssetAsyncLoader::Priority::Normal;
|
||||
task.work = [this, path, handle]() { *handle = loadShader(path); };
|
||||
task.onComplete = [handle, callback]() {
|
||||
if (callback) {
|
||||
callback(*handle);
|
||||
}
|
||||
};
|
||||
asyncRuntime_.submit(task);
|
||||
}
|
||||
|
||||
void AssetSystem::processAsyncCallbacks() { asyncRuntime_.processCallbacks(); }
|
||||
|
||||
void AssetSystem::registerTextureLoader(
|
||||
std::unique_ptr<AssetLoader<Texture>> loader) {
|
||||
textureLoader_ = std::move(loader);
|
||||
}
|
||||
|
||||
void AssetSystem::registerShaderLoader(std::unique_ptr<AssetLoader<Shader>> loader) {
|
||||
shaderLoader_ = std::move(loader);
|
||||
}
|
||||
|
||||
bool AssetSystem::createDefaults() { return builtinFactory_.create(); }
|
||||
|
||||
void AssetSystem::destroyDefaults() { builtinFactory_.destroy(); }
|
||||
|
||||
Handle<Texture> AssetSystem::defaultTexture() const {
|
||||
return builtinFactory_.defaultTexture();
|
||||
}
|
||||
|
||||
Handle<Shader> AssetSystem::defaultShader() const {
|
||||
return builtinFactory_.defaultShader();
|
||||
}
|
||||
|
||||
Handle<Material> AssetSystem::defaultMaterial() const {
|
||||
return builtinFactory_.defaultMaterial();
|
||||
}
|
||||
|
||||
Handle<Mesh> AssetSystem::defaultQuad() const {
|
||||
return builtinFactory_.defaultQuad();
|
||||
}
|
||||
|
||||
void AssetSystem::enableHotReload(bool enable) { hotReloadRuntime_.enable(enable); }
|
||||
|
||||
void AssetSystem::setHotReloadInterval(float interval) {
|
||||
hotReloadRuntime_.setInterval(interval);
|
||||
}
|
||||
|
||||
void AssetSystem::checkForChanges() {
|
||||
hotReloadRuntime_.check(
|
||||
[this](const AssetHotReloader::FileWatchInfo &info) { reloadTexture(info); },
|
||||
[this](const AssetHotReloader::FileWatchInfo &info) { reloadShader(info); });
|
||||
}
|
||||
|
||||
void AssetSystem::reloadTexture(const AssetHotReloader::FileWatchInfo &info) {
|
||||
if (!info.textureHandle.isValid()) {
|
||||
return;
|
||||
}
|
||||
Texture *texture = textures_.get(info.textureHandle);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
if (!texture->reloadFromFile(info.path)) {
|
||||
return;
|
||||
}
|
||||
notifyTextureReloaded(info.textureHandle);
|
||||
}
|
||||
|
||||
void AssetSystem::reloadShader(const AssetHotReloader::FileWatchInfo &info) {
|
||||
if (!info.shaderHandle.isValid()) {
|
||||
return;
|
||||
}
|
||||
Shader *shader = shaders_.get(info.shaderHandle);
|
||||
if (!shader) {
|
||||
return;
|
||||
}
|
||||
std::string key = shaderCache_.findKeyByHandle(info.shaderHandle);
|
||||
size_t sep = key.find('|');
|
||||
if (sep == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
std::string vertPath = key.substr(0, sep);
|
||||
std::string fragPath = key.substr(sep + 1);
|
||||
std::string vsSource = fileSystem_.readString(vertPath);
|
||||
std::string fsSource = fileSystem_.readString(fragPath);
|
||||
if (vsSource.empty() || fsSource.empty()) {
|
||||
return;
|
||||
}
|
||||
if (!shader->reloadFromSource(vsSource, fsSource)) {
|
||||
return;
|
||||
}
|
||||
notifyShaderReloaded(info.shaderHandle);
|
||||
}
|
||||
|
||||
void AssetSystem::registerDependency(Handle<Material> material,
|
||||
Handle<Texture> texture) {
|
||||
dependencyGraph_.registerDependency(material, texture);
|
||||
}
|
||||
|
||||
void AssetSystem::registerDependency(Handle<Material> material,
|
||||
Handle<Shader> shader) {
|
||||
dependencyGraph_.registerDependency(material, shader);
|
||||
}
|
||||
|
||||
void AssetSystem::notifyTextureReloaded(Handle<Texture> texture) {
|
||||
dependencyGraph_.notifyTextureReloaded(texture, [](Handle<Material>) {});
|
||||
}
|
||||
|
||||
void AssetSystem::notifyShaderReloaded(Handle<Shader> shader) {
|
||||
dependencyGraph_.notifyShaderReloaded(shader, [this, shader](Handle<Material> material) {
|
||||
Material *ptr = materials_.get(material);
|
||||
if (ptr) {
|
||||
ptr->setShader(shaders_.getPtr(shader));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AssetSystem::clear() {
|
||||
shutdownAsync();
|
||||
hotReloadRuntime_.clear();
|
||||
dependencyGraph_.clear();
|
||||
textureCache_.clear();
|
||||
shaderCache_.clear();
|
||||
}
|
||||
|
||||
AssetSystem::Stats AssetSystem::stats() const {
|
||||
Stats s;
|
||||
s.textureCount = textures_.count();
|
||||
s.shaderCount = shaders_.count();
|
||||
s.materialCount = materials_.count();
|
||||
s.meshCount = meshes_.count();
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#include <algorithm>
|
||||
#include <assets/dependency/asset_dependency_graph.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
void AssetDependencyGraph::clear() {
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
textureDeps_.clear();
|
||||
shaderDeps_.clear();
|
||||
}
|
||||
|
||||
void AssetDependencyGraph::registerDependency(Handle<Material> material,
|
||||
Handle<Texture> texture) {
|
||||
if (!material.isValid() || !texture.isValid()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
auto &deps = textureDeps_[texture.index()];
|
||||
deps.texture = texture;
|
||||
auto it = std::find(deps.materials.begin(), deps.materials.end(), material);
|
||||
if (it == deps.materials.end()) {
|
||||
deps.materials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDependencyGraph::registerDependency(Handle<Material> material,
|
||||
Handle<Shader> shader) {
|
||||
if (!material.isValid() || !shader.isValid()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
auto &deps = shaderDeps_[shader.index()];
|
||||
deps.shader = shader;
|
||||
auto it = std::find(deps.materials.begin(), deps.materials.end(), material);
|
||||
if (it == deps.materials.end()) {
|
||||
deps.materials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDependencyGraph::notifyTextureReloaded(
|
||||
Handle<Texture> texture,
|
||||
const std::function<void(Handle<Material>)> &onMaterialUpdate) const {
|
||||
if (!texture.isValid()) {
|
||||
return;
|
||||
}
|
||||
std::vector<Handle<Material>> materials;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = textureDeps_.find(texture.index());
|
||||
if (it == textureDeps_.end()) {
|
||||
return;
|
||||
}
|
||||
materials = it->second.materials;
|
||||
}
|
||||
for (const auto &material : materials) {
|
||||
onMaterialUpdate(material);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDependencyGraph::notifyShaderReloaded(
|
||||
Handle<Shader> shader,
|
||||
const std::function<void(Handle<Material>)> &onMaterialUpdate) const {
|
||||
if (!shader.isValid()) {
|
||||
return;
|
||||
}
|
||||
std::vector<Handle<Material>> materials;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = shaderDeps_.find(shader.index());
|
||||
if (it == shaderDeps_.end()) {
|
||||
return;
|
||||
}
|
||||
materials = it->second.materials;
|
||||
}
|
||||
for (const auto &material : materials) {
|
||||
onMaterialUpdate(material);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#include <algorithm>
|
||||
#include <assets/deps/asset_dependency_tracker.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
void AssetDependencyTracker::clear() {
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
textureDependencies_.clear();
|
||||
shaderDependencies_.clear();
|
||||
}
|
||||
|
||||
void AssetDependencyTracker::registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Texture> texture) {
|
||||
if (!material.isValid() || !texture.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
auto &info = textureDependencies_[texture.index()];
|
||||
info.texture = texture;
|
||||
auto it = std::find(info.dependentMaterials.begin(),
|
||||
info.dependentMaterials.end(), material);
|
||||
if (it == info.dependentMaterials.end()) {
|
||||
info.dependentMaterials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDependencyTracker::registerMaterialDependency(Handle<Material> material,
|
||||
Handle<Shader> shader) {
|
||||
if (!material.isValid() || !shader.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||
auto &info = shaderDependencies_[shader.index()];
|
||||
info.shader = shader;
|
||||
auto it = std::find(info.dependentMaterials.begin(),
|
||||
info.dependentMaterials.end(), material);
|
||||
if (it == info.dependentMaterials.end()) {
|
||||
info.dependentMaterials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDependencyTracker::notifyTextureReloaded(
|
||||
Handle<Texture> texture,
|
||||
const std::function<void(Handle<Material>)> &onMaterialUpdate) const {
|
||||
if (!texture.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Handle<Material>> materials;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = textureDependencies_.find(texture.index());
|
||||
if (it == textureDependencies_.end()) {
|
||||
return;
|
||||
}
|
||||
materials = it->second.dependentMaterials;
|
||||
}
|
||||
|
||||
for (const auto &material : materials) {
|
||||
onMaterialUpdate(material);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDependencyTracker::notifyShaderReloaded(
|
||||
Handle<Shader> shader,
|
||||
const std::function<void(Handle<Material>)> &onMaterialUpdate) const {
|
||||
if (!shader.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Handle<Material>> materials;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||
auto it = shaderDependencies_.find(shader.index());
|
||||
if (it == shaderDependencies_.end()) {
|
||||
return;
|
||||
}
|
||||
materials = it->second.dependentMaterials;
|
||||
}
|
||||
|
||||
for (const auto &material : materials) {
|
||||
onMaterialUpdate(material);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#include <assets/runtime/asset_async_runtime.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
void AssetAsyncRuntime::init(uint32_t threadCount) { loader_.init(threadCount); }
|
||||
|
||||
void AssetAsyncRuntime::shutdown() { loader_.shutdown(); }
|
||||
|
||||
bool AssetAsyncRuntime::running() const { return loader_.isRunning(); }
|
||||
|
||||
void AssetAsyncRuntime::submit(const AssetAsyncLoader::Task &task) {
|
||||
loader_.submit(task);
|
||||
}
|
||||
|
||||
void AssetAsyncRuntime::processCallbacks() { loader_.processCallbacks(); }
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#include <assets/runtime/asset_hot_reload_runtime.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
AssetHotReloadRuntime::AssetHotReloadRuntime(const AssetFileSystem &fileSystem)
|
||||
: reloader_(fileSystem) {}
|
||||
|
||||
void AssetHotReloadRuntime::enable(bool enable) { reloader_.enable(enable); }
|
||||
|
||||
bool AssetHotReloadRuntime::enabled() const { return reloader_.enabled(); }
|
||||
|
||||
void AssetHotReloadRuntime::setInterval(float interval) {
|
||||
reloader_.setInterval(interval);
|
||||
}
|
||||
|
||||
void AssetHotReloadRuntime::addWatch(const std::string &path,
|
||||
Handle<Texture> handle) {
|
||||
reloader_.addFileWatch(path, handle);
|
||||
}
|
||||
|
||||
void AssetHotReloadRuntime::addWatch(const std::string &path,
|
||||
Handle<Shader> handle) {
|
||||
reloader_.addFileWatch(path, handle);
|
||||
}
|
||||
|
||||
void AssetHotReloadRuntime::clear() { reloader_.clear(); }
|
||||
|
||||
void AssetHotReloadRuntime::check(
|
||||
const std::function<void(const AssetHotReloader::FileWatchInfo &)>
|
||||
&reloadTexture,
|
||||
const std::function<void(const AssetHotReloader::FileWatchInfo &)>
|
||||
&reloadShader) {
|
||||
reloader_.checkForChanges(reloadTexture, reloadShader);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
Loading…
Reference in New Issue