Add texture atlas implementation

This commit is contained in:
Nikita Lisitsa 2022-02-10 13:29:47 +03:00
parent 93fd269c02
commit 45b3369bc9
2 changed files with 156 additions and 0 deletions

View file

@ -0,0 +1,75 @@
#pragma once
#include <psemek/util/atlas.hpp>
#include <psemek/gfx/texture.hpp>
#include <psemek/gfx/texture_view.hpp>
namespace psemek::gfx
{
template <typename Pixel, typename Key, typename Compare = std::less<Key>>
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<texture_view, bool> insert(Key const & key, util::array<Pixel, 2> const & data);
texture_view find(Key const & key) const;
texture_view at(Key const & key) const;
private:
util::atlas<Pixel, 2, Key, Compare> atlas_;
texture_2d texture_;
void update_texture();
texture_view to_view(typename util::atlas<Pixel, 2, Key, Compare>::atlas_part const & part) const;
};
template <typename Pixel, typename Key, typename Compare>
texture_atlas_2d<Pixel, Key, Compare>::texture_atlas_2d(Pixel background, Compare compare)
: atlas_(std::move(background), std::move(compare))
{}
template <typename Pixel, typename Key, typename Compare>
std::pair<texture_view_2d, bool> texture_atlas_2d<Pixel, Key, Compare>::insert(Key const & key, util::array<Pixel, 2> const & data)
{
auto result = atlas_.insert(key, data);
if (result.second)
update_texture();
return {to_view(result.first), result.second};
}
template <typename Pixel, typename Key, typename Compare>
texture_view_2d texture_atlas_2d<Pixel, Key, Compare>::find(Key const & key) const
{
auto result = atlas_.find(key);
if (result)
return to_view(*result);
return texture_view{};
}
template <typename Pixel, typename Key, typename Compare>
texture_view_2d texture_atlas_2d<Pixel, Key, Compare>::at(Key const & key) const
{
return to_view(atlas_.at(key));
}
template <typename Pixel, typename Key, typename Compare>
void texture_atlas_2d<Pixel, Key, Compare>::update_texture()
{
texture_.load(atlas_.array());
}
template <typename Pixel, typename Key, typename Compare>
texture_view_2d texture_atlas_2d<Pixel, Key, Compare>::to_view(typename util::atlas<Pixel, 2, Key, Compare>::atlas_part const & part) const
{
return texture_view{&texture_, {{{part.begin[0], part.end[0]}, {part.begin[1], part.end[1]}}}};
}
}

View file

@ -0,0 +1,81 @@
#pragma once
#include <psemek/util/array.hpp>
#include <map>
#include <optional>
namespace psemek::util
{
template <typename T, std::size_t N, typename Key, typename Compare = std::less<Key>>
struct atlas;
template <typename T, typename Key, typename Compare>
struct atlas<T, 2, Key, Compare>
{
struct atlas_part
{
std::array<std::size_t, 2> begin;
std::array<std::size_t, 2> end;
};
atlas(T default_value = T{}, Compare compare = Compare{})
: default_value_(std::move(default_value))
, data_(std::move(compare))
{}
util::array<T, 2> const & array() const
{
return array_;
}
std::pair<atlas_part, bool> insert(Key const & key, util::array<T, 2> 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<atlas_part> 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<Key, atlas_part, Compare> data_;
util::array<T, 2> array_;
};
}