Extra2D/src/assets/assets_module.cpp

405 lines
12 KiB
C++
Raw Normal View History

#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() { g_assetsModule = this; }
AssetsModule::~AssetsModule() {
if (g_assetsModule == this) {
g_assetsModule = nullptr;
}
}
bool AssetsModule::init() {
E2D_LOG_INFO("AssetsModule initializing...");
textureLoader_ = std::make_unique<TextureLoader>();
shaderLoader_ = std::make_unique<ShaderLoader>();
// 监听窗口显示事件,在 OpenGL 上下文创建完成后创建默认资源
onShowListener_ = std::make_unique<events::OnShow::Listener>();
onShowListener_->bind([this]() { this->onGLContextReady(); });
E2D_LOG_INFO(
"AssetsModule initialized successfully (waiting for GL context)");
return true;
}
void AssetsModule::onGLContextReady() {
if (defaultResourcesCreated_) {
return;
}
E2D_LOG_INFO("OpenGL context ready, creating default resources...");
if (!createDefaultResources()) {
E2D_LOG_ERROR("Failed to create default resources");
return;
}
defaultResourcesCreated_ = true;
E2D_LOG_INFO("Default resources created successfully");
}
void AssetsModule::shutdown() {
E2D_LOG_INFO("AssetsModule shutting down...");
// 释放事件监听器
onShowListener_.reset();
destroyDefaultResources();
textures_.clear();
shaders_.clear();
materials_.clear();
meshes_.clear();
texturePathCache_.clear();
shaderPathCache_.clear();
textureLoader_.reset();
shaderLoader_.reset();
defaultResourcesCreated_ = false;
E2D_LOG_INFO("AssetsModule shutdown complete");
}
AssetsModule *getAssets() { return g_assetsModule; }
//===========================================================================
// Texture 加载特化
//===========================================================================
template <>
Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
auto it = texturePathCache_.find(path);
if (it != texturePathCache_.end()) {
if (textures_.isValid(it->second)) {
return it->second;
}
texturePathCache_.erase(it);
}
if (!textureLoader_) {
E2D_LOG_ERROR("TextureLoader not registered");
return Handle<Texture>::invalid();
}
Ptr<Texture> texture = textureLoader_->load(path);
if (!texture) {
E2D_LOG_ERROR("Failed to load texture: {}", path);
return Handle<Texture>::invalid();
}
Handle<Texture> handle = textures_.insert(texture);
texturePathCache_[path] = handle;
E2D_LOG_DEBUG("Loaded texture: {} -> handle index {}", path, handle.index());
return handle;
}
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_LOG_ERROR("TextureLoader not registered");
return Handle<Texture>::invalid();
}
Ptr<Texture> texture = textureLoader_->loadFromMemory(data, size);
if (!texture) {
E2D_LOG_ERROR("Failed to load texture from memory: {}", key);
return Handle<Texture>::invalid();
}
Handle<Texture> handle = textures_.insert(texture);
texturePathCache_[key] = handle;
return handle;
}
//===========================================================================
// Shader 加载特化
//===========================================================================
template <> Handle<Shader> AssetsModule::load<Shader>(const std::string &path) {
auto it = shaderPathCache_.find(path);
if (it != shaderPathCache_.end()) {
if (shaders_.isValid(it->second)) {
return it->second;
}
shaderPathCache_.erase(it);
}
if (!shaderLoader_) {
E2D_LOG_ERROR("ShaderLoader not registered");
return Handle<Shader>::invalid();
}
Ptr<Shader> shader = shaderLoader_->load(path);
if (!shader) {
E2D_LOG_ERROR("Failed to load shader: {}", path);
return Handle<Shader>::invalid();
}
Handle<Shader> handle = shaders_.insert(shader);
shaderPathCache_[path] = handle;
E2D_LOG_DEBUG("Loaded shader: {} -> handle index {}", path, handle.index());
return handle;
}
template <>
Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
const std::string &fragPath) {
std::string cacheKey = vertPath + "|" + fragPath;
auto it = shaderPathCache_.find(cacheKey);
if (it != shaderPathCache_.end()) {
if (shaders_.isValid(it->second)) {
return it->second;
}
shaderPathCache_.erase(it);
}
if (!shaderLoader_) {
E2D_LOG_ERROR("ShaderLoader not registered");
return Handle<Shader>::invalid();
}
ShaderLoader *shaderLoader = static_cast<ShaderLoader *>(shaderLoader_.get());
Ptr<Shader> shader = shaderLoader->load(vertPath, fragPath);
if (!shader) {
E2D_LOG_ERROR("Failed to load shader: {} + {}", vertPath, fragPath);
return Handle<Shader>::invalid();
}
Handle<Shader> handle = shaders_.insert(shader);
shaderPathCache_[cacheKey] = handle;
E2D_LOG_DEBUG("Loaded shader: {} + {} -> handle index {}", vertPath, fragPath,
handle.index());
return handle;
}
//===========================================================================
// 批量加载
//===========================================================================
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 (!std::filesystem::exists(dirPath)) {
E2D_LOG_WARN("Directory not found: {}", 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_LOG_ERROR("Error loading directory {}: {}", directory, e.what());
}
E2D_LOG_DEBUG("Loaded {} textures from {}", handles.size(), directory);
return handles;
}
//===========================================================================
// 异步加载
//===========================================================================
template <>
void AssetsModule::loadAsync<Texture>(
const std::string &path, std::function<void(Handle<Texture>)> callback) {
std::thread([this, path, callback]() {
Handle<Texture> handle = load<Texture>(path);
if (callback) {
callback(handle);
}
}).detach();
}
//===========================================================================
// 加载器注册
//===========================================================================
template <>
void AssetsModule::registerLoader<Texture>(
std::unique_ptr<AssetLoader<Texture>> loader) {
textureLoader_ = std::move(loader);
}
template <>
void AssetsModule::registerLoader<Shader>(
std::unique_ptr<AssetLoader<Shader>> loader) {
shaderLoader_ = 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_LOG_ERROR("Failed to create default texture");
return false;
}
defaultTexture_ = textures_.insert(texture);
E2D_LOG_DEBUG("Created default texture");
}
{
// 从文件加载默认着色器
std::filesystem::path vertPath = "shader/default.vert";
std::filesystem::path fragPath = "shader/default.frag";
Ptr<Shader> shader = makePtr<Shader>();
if (!std::filesystem::exists(vertPath) ||
!std::filesystem::exists(fragPath)) {
E2D_LOG_ERROR("Default shader files not found: {}, {}", vertPath.string(),
fragPath.string());
return false;
}
if (!shader->loadFromFile(vertPath.string(), fragPath.string())) {
E2D_LOG_ERROR("Failed to load default shader from files: {}, {}",
vertPath.string(), fragPath.string());
return false;
}
defaultShader_ = shaders_.insert(shader);
E2D_LOG_DEBUG("Loaded default shader from files: {}, {}", vertPath.string(),
fragPath.string());
}
{
Ptr<Material> material = makePtr<Material>();
material->setShader(getPtr(defaultShader_));
defaultMaterial_ = materials_.insert(material);
E2D_LOG_DEBUG("Created default material");
}
{
Ptr<Mesh> mesh = Mesh::createQuad(Vec2(1.0f, 1.0f));
if (!mesh) {
E2D_LOG_ERROR("Failed to create default quad mesh");
return false;
}
defaultQuad_ = meshes_.insert(mesh);
E2D_LOG_DEBUG("Created default quad mesh");
}
return true;
}
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();
}
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_);
}
Shader *AssetsModule::getDefaultShaderPtr() {
return shaders_.get(defaultShader_);
}
Material *AssetsModule::getDefaultMaterialPtr() {
return materials_.get(defaultMaterial_);
}
Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(defaultQuad_); }
//===========================================================================
// 热重载
//===========================================================================
void AssetsModule::enableHotReload(bool enable) { hotReloadEnabled_ = enable; }
void AssetsModule::checkForChanges() {}
//===========================================================================
// 统计
//===========================================================================
AssetsModule::Stats AssetsModule::getStats() const {
Stats stats;
stats.textureCount = textures_.count();
stats.shaderCount = shaders_.count();
stats.materialCount = materials_.count();
stats.meshCount = meshes_.count();
return stats;
}
} // namespace extra2d