/* * * Copyright (C) 2023 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BLT_WITH_GRAPHICS_RESOURCE_MANAGER_H #define BLT_WITH_GRAPHICS_RESOURCE_MANAGER_H #include #include #include #include #include #include #include #include #include "blt/compatibility.h" #include "blt/iterator/enumerate.h" namespace blt::gfx { struct texture_info { public: texture_info() = default; explicit texture_info(std::string path, std::string name): path(std::move(path)), name(std::move(name)) {} BLT_MAKE_GETTER(std::string, path); BLT_MAKE_GETTER(std::string, name); BLT_MAKE_GETTER_AND_SETTER(blt::i32, desired_width); BLT_MAKE_GETTER_AND_SETTER(blt::i32, desired_height); BLT_MAKE_GETTER_AND_SETTER(blt::i32, desired_channels); private: std::string path; std::string name; blt::i32 desired_width = 0; blt::i32 desired_height = 0; blt::i32 desired_channels = 0; }; class texture_array { public: texture_array(std::string name, i32 width, i32 height, blt::i32 channels = 4): name(std::move(name)), width(width), height(height), channels(channels) {} void add_texture(std::string path, std::string t_name = "") { textures.push_back(texture_info{std::move(path), std::move(t_name)}.set_desired_width(width).set_desired_height(height) .set_desired_channels(channels)); } BLT_MAKE_GETTER(std::vector, textures); BLT_MAKE_GETTER(std::string, name); private: std::vector textures; std::string name; i32 width; i32 height; i32 channels; }; class resource_manager { private: struct texture_destination { std::vector* vec = nullptr; std::optional order = {}; texture_destination() = default; explicit texture_destination(std::vector* vec): vec(vec) {} explicit texture_destination(std::vector* vec, blt::size_t order): vec(vec), order(order) {} void add(texture_file* file) const { // if order is present the vec is assumed to be resized. otherwise assume order doesn't matter and push to an empty vec if (order) (*vec)[*order] = file; else vec->push_back(file); } }; std::mutex load_lock; std::mutex save_lock; std::vector> textures_to_load; std::vector loaded_textures; std::vector>> loaded_arrays; blt::hashmap_t textures_2d; blt::hashmap_t texture_arrays_2d; std::string resource_prefix; void load_to_gl(); public: resource_manager() = default; explicit resource_manager(std::string_view resource_prefix): resource_prefix(resource_prefix) { if (!blt::string::ends_with(this->resource_prefix, "/")) this->resource_prefix += '/'; } void enqueue(std::string path, std::string name = "") { textures_to_load.emplace_back(texture_destination{&loaded_textures}, texture_info{std::move(path), std::move(name)}); } void with(texture_info info) { textures_to_load.emplace_back(texture_destination{&loaded_textures}, std::move(info)); } void with(texture_array array) { loaded_arrays.emplace_back(array.get_name(), std::vector{}); auto& dest = loaded_arrays.back(); dest.second.reserve(array.get_textures().size()); dest.second.resize(array.get_textures().size()); for (const auto& [index, texture] : blt::enumerate(array.get_textures())) textures_to_load.emplace_back(texture_destination{&dest.second, index}, std::move(texture)); } void load_resources(std::size_t threads = 8); inline std::optional get(const std::string& name) { if (name.empty() || textures_2d.find(name) == textures_2d.end()) return {}; return textures_2d[name]; } /** * Directly sets the internal representation of the texture. Can be used to set custom, non file system loaded textures. * Note: this function takes ownership of the ptr. */ inline void set(std::string_view name, texture_gl2D* texture) { textures_2d[name] = texture; } /** * Sets the directory used to prefix all asset loading with */ inline void setPrefixDirectory(std::string path) { if (!blt::string::ends_with(resource_prefix, "/")) resource_prefix += '/'; resource_prefix = std::move(path); } void cleanup(); }; } #endif //BLT_WITH_GRAPHICS_RESOURCE_MANAGER_H