#include #include #include "assets.h" #include "texture.h" //#define AL_LOG_ENABLE_TRACE #include "log.h" namespace Mauri { static AssetManager asset_manager_; auto asset_manager() -> AssetManager * { return &asset_manager_; } } // namespace Mauri using namespace Mauri; Asset::Asset() { this->type = ASSET_VOID; this->size = 0; this->data = nullptr; } static Asset asset_void = Asset(); Asset::Asset(const std::string &path, byte *start, byte *end) : path(path) { this->type = ASSET_SLICE; this->size = end - start; this->data = start; this->hash = std::hash{}(path); } Asset::Asset(const std::string &path) : path(path) { std::ifstream file(path, std::ios::binary | std::ios::ate); if (file.bad() || file.fail()) { this->type = ASSET_VOID; file.close(); return; } this->size = file.tellg(); this->data = new byte[size]; file.seekg(0, std::ios::beg); if (!file.read(reinterpret_cast(this->data), this->size)) { this->type = ASSET_VOID; file.close(); delete[] this->data; return; } file.close(); this->type = ASSET_FILE; } Asset::~Asset() { if (this->type == ASSET_VOID) return; if (this->type == ASSET_FILE) delete[] this->data; if (this->lasset) { switch (this->ltype) { case TEXTURE: delete (Texture *)this->lasset; break; default: break; } } } auto AssetManager::arm_package(const std::string &path, bool can_output) -> bool { this->package = new Asset(path); if (this->package->type == ASSET_VOID) { error("failed to load package file: (%s)", path.c_str()); return false; } std::string_view signature = this->package->reads(this->package->read()); if (signature.compare(0, 4, "PKGV") != 0) { error("invalid package file: (%s)", path.c_str()); return false; } u32 count = this->package->read(); this->assets.resize(count); std::vector package_assets; package_assets.resize(count); for (u32 i = 0; i < count; i++) { package_assets[i] = PackageFile{ this->package->reads(this->package->read()), this->package->read(), this->package->read() }; } for (u32 i = 0; i < count; i++) { const PackageFile &asset = package_assets[i]; byte *start = this->package->ptr() + asset.offset; byte *end = start + asset.length; this->assets[i] = new Asset(std::string(asset.path), start, end); debug("package file: (%s)", this->assets[i]->path.c_str()); } this->prepare_output = can_output; return true; } auto AssetManager::add_search_directory(const std::string &directory) -> bool { if (!std::filesystem::is_directory(directory)) return false; this->directories.push_back(directory); return true; } auto AssetManager::get(const std::string &part, AssetTypeHint hint) -> Asset * { std::string path = part; switch (hint) { case TEXTURE: path.insert(0, "materials/"); path.append(".tex"); break; case SHADER: path.insert(0, "shaders/"); break; case VERTEX_SHADER: path.insert(0, "shaders/"); path.append(".vert"); break; case FRAGMENT_SHADER: path.insert(0, "shaders/"); path.append(".frag"); break; case NONE: default: break; } Asset *asset = nullptr; u64 hash = std::hash{}(path); for (u32 i = 0; i < this->assets.size(); i++) { if (this->assets[i]->hash == hash) { asset = this->assets[i]; break; } } if (!asset) { for (std::string &dir : this->directories) { std::string attempt = dir + "/" + path; asset = new Asset(attempt); if (asset->type == ASSET_VOID) { delete asset; asset = nullptr; continue; } asset->hash = hash; trace("found asset in: (%s)", dir.c_str()); break; } if (!asset) { error("failed to load asset: (%s)", path.c_str()); return &asset_void; } debug("fetched asset: (%s)", path.c_str()); this->assets.push_back(asset); } asset->ltype = hint; if (!asset->lasset) { switch (asset->ltype) { case TEXTURE: asset->lasset = new Texture(asset); debug("processed texture: (%s)", path.c_str()); break; default: break; } } return asset; } auto AssetManager::dump(const std::string &output_path) -> void { if (!std::filesystem::is_directory(output_path) && !std::filesystem::create_directories(output_path)) { error("failed to create directory: (%s)", output_path.c_str()); return; } for (Asset *asset : this->assets) { std::stringstream path; path << output_path; if (output_path.back() != '/') path << '/'; size_t index = asset->path.find_last_of('/'); if (index != std::string::npos) { std::filesystem::create_directories(path.str() + asset->path.substr(0, index)); } path << asset->path; switch (asset->ltype) { case TEXTURE: { Texture *texture = ((Texture *)asset->lasset); texture->save_to_file(path.str() + ".png"); std::ofstream file(path.str() + ".flags"); file << "NO_INTERPOLATION " << texture->flags.m.NO_INTERPOLATION << "\n"; file << "CLAMP_UV " << texture->flags.m.CLAMP_UV << "\n"; file << "IS_GIF " << texture->flags.m.IS_GIF << "\n"; file.close(); break; } case VERTEX_SHADER: case FRAGMENT_SHADER: case SHADER: { std::ofstream file(path.str()); file << asset->as_string(); file.close(); break; } case NONE: { std::ofstream file(path.str(), std::ios::binary); file << asset->as_string(); file.close(); break; } } } } auto AssetManager::unload_package() -> void { for (Asset *asset : this->assets) { delete asset; } this->assets.clear(); delete this->package; }