/* * <Short Description> * 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 <https://www.gnu.org/licenses/>. */ #ifndef BLT_WITH_GRAPHICS_RESOURCE_MANAGER_H #define BLT_WITH_GRAPHICS_RESOURCE_MANAGER_H #include <blt/std/hashmap.h> #include <blt/std/string.h> #include <blt/meta/config_generator.h> #include <blt/gfx/texture.h> #include <mutex> #include <vector> #include <optional> #include <string> #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<texture_info>, textures); BLT_MAKE_GETTER(std::string, name); private: std::vector<texture_info> textures; std::string name; i32 width; i32 height; i32 channels; }; class resource_manager { private: struct texture_destination { std::vector<texture_file*>* vec = nullptr; std::optional<blt::size_t> order = {}; texture_destination() = default; explicit texture_destination(std::vector<texture_file*>* vec): vec(vec) {} explicit texture_destination(std::vector<texture_file*>* 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<std::pair<texture_destination, texture_info>> textures_to_load; std::vector<texture_file*> loaded_textures; std::vector<std::pair<std::string, std::vector<texture_file*>>> loaded_arrays; blt::hashmap_t<std::string, texture_gl2D*> textures_2d; blt::hashmap_t<std::string, gl_texture2D_array*> 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<texture_file*>{}); 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<texture_gl2D*> 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