Add texture atlas implementation
This commit is contained in:
parent
93fd269c02
commit
45b3369bc9
2 changed files with 156 additions and 0 deletions
75
libs/gfx/include/psemek/gfx/texture_atlas.hpp
Normal file
75
libs/gfx/include/psemek/gfx/texture_atlas.hpp
Normal 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]}}}};
|
||||
}
|
||||
|
||||
}
|
||||
81
libs/util/include/psemek/util/atlas.hpp
Normal file
81
libs/util/include/psemek/util/atlas.hpp
Normal 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_;
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue