From 45b3369bc9516eab3e193be07cb73a926db7dc8a Mon Sep 17 00:00:00 2001 From: lisyarus Date: Thu, 10 Feb 2022 13:29:47 +0300 Subject: [PATCH] Add texture atlas implementation --- libs/gfx/include/psemek/gfx/texture_atlas.hpp | 75 +++++++++++++++++ libs/util/include/psemek/util/atlas.hpp | 81 +++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 libs/gfx/include/psemek/gfx/texture_atlas.hpp create mode 100644 libs/util/include/psemek/util/atlas.hpp diff --git a/libs/gfx/include/psemek/gfx/texture_atlas.hpp b/libs/gfx/include/psemek/gfx/texture_atlas.hpp new file mode 100644 index 00000000..afd192b0 --- /dev/null +++ b/libs/gfx/include/psemek/gfx/texture_atlas.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include + +namespace psemek::gfx +{ + + template > + struct texture_atlas_2d + { + texture_atlas_2d(Pixel background = Pixel{}, Compare compare = Compare{}); + + using texture_view = texture_view_2d; + + texture_2d & texture() { return texture_; } + texture_2d const & texture() const { return texture_; } + + std::pair insert(Key const & key, util::array const & data); + texture_view find(Key const & key) const; + texture_view at(Key const & key) const; + + private: + util::atlas atlas_; + texture_2d texture_; + + void update_texture(); + + texture_view to_view(typename util::atlas::atlas_part const & part) const; + }; + + template + texture_atlas_2d::texture_atlas_2d(Pixel background, Compare compare) + : atlas_(std::move(background), std::move(compare)) + {} + + template + std::pair texture_atlas_2d::insert(Key const & key, util::array const & data) + { + auto result = atlas_.insert(key, data); + if (result.second) + update_texture(); + + return {to_view(result.first), result.second}; + } + + template + texture_view_2d texture_atlas_2d::find(Key const & key) const + { + auto result = atlas_.find(key); + if (result) + return to_view(*result); + return texture_view{}; + } + + template + texture_view_2d texture_atlas_2d::at(Key const & key) const + { + return to_view(atlas_.at(key)); + } + + template + void texture_atlas_2d::update_texture() + { + texture_.load(atlas_.array()); + } + + template + texture_view_2d texture_atlas_2d::to_view(typename util::atlas::atlas_part const & part) const + { + return texture_view{&texture_, {{{part.begin[0], part.end[0]}, {part.begin[1], part.end[1]}}}}; + } + +} diff --git a/libs/util/include/psemek/util/atlas.hpp b/libs/util/include/psemek/util/atlas.hpp new file mode 100644 index 00000000..3cd894eb --- /dev/null +++ b/libs/util/include/psemek/util/atlas.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include +#include + +namespace psemek::util +{ + + template > + struct atlas; + + template + struct atlas + { + struct atlas_part + { + std::array begin; + std::array end; + }; + + atlas(T default_value = T{}, Compare compare = Compare{}) + : default_value_(std::move(default_value)) + , data_(std::move(compare)) + {} + + util::array const & array() const + { + return array_; + } + + std::pair insert(Key const & key, util::array const & data) + { + auto it = data_.find(key); + if (it != data_.end()) + return {it->second, false}; + + atlas_part part; + part.begin[0] = array_.width(); + part.end[0] = part.begin[0] + data.width(); + part.begin[1] = 0; + part.end[1] = data.height(); + + std::size_t new_width = array_.width() + data.width(); + std::size_t new_height = std::max(array_.height(), data.height()); + + array_.resize({new_width, new_height}, default_value_); + + for (std::size_t y = 0; y < data.height(); ++y) + { + for (std::size_t x = 0; x < data.width(); ++x) + { + array_(part.begin[0] + x, part.begin[1] + y) = data(x, y); + } + } + + data_[key] = part; + return {part, true}; + } + + std::optional find(Key const & key) const + { + auto it = data_.find(key); + if (it != data_.end()) + return it->second; + return std::nullopt; + } + + atlas_part at(Key const & key) const + { + return data_.at(key); + } + + private: + T default_value_; + std::map data_; + util::array array_; + }; + +}