1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#include "wall-atlas.hpp"
#include "compat/assert.hpp"
#include <utility>
#include <Magnum/ImageView.h>
#include <Magnum/GL/TextureFormat.h>
namespace floormat {
namespace {
inline uint8_t direction_count_(std::array<uint8_t, 4> rot_to_direction)
{
uint8_t total = 0;
for (uint8_t x : rot_to_direction)
if (x != (uint8_t)-1)
total++;
return total;
}
} // namespace
namespace Wall {
} // namespace Wall
wall_atlas::wall_atlas() noexcept = default;
wall_atlas::~wall_atlas() noexcept = default;
wall_atlas::wall_atlas(Info info, const ImageView2D& image,
Array<Frame> frames,
Array<Direction> directions,
std::array<DirArrayIndex, 4> direction_to_DirArrayIndex)
: _dir_array{ std::move(directions) }, _frame_array{ std::move(frames) },
_info{ std::move(info) },
_direction_to_Direction_array_index{ direction_to_DirArrayIndex }
{
_texture.setLabel(_info.name)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setMagnificationFilter(GL::SamplerFilter::Nearest)
.setMinificationFilter(GL::SamplerFilter::Linear)
.setMaxAnisotropy(1) // todo?
.setBorderColor(Color4{1, 0, 0, 1})
.setStorage(1, GL::textureFormat(image.format()), image.size())
.setSubImage(0, {}, image);
}
auto wall_atlas::get_Direction(Direction_ num) const -> Direction*
{
fm_debug_assert(num < Direction_::COUNT);
if (_dir_array.isEmpty()) [[unlikely]]
return {};
if (auto idx = _direction_to_Direction_array_index[(uint8_t)num])
return const_cast<Direction*>(&_dir_array[idx.val]);
return {};
}
auto wall_atlas::frames(const Group& group) const -> ArrayView<const Frame>
{
if (_frame_array.isEmpty()) [[unlikely]]
return {};
const auto size = _frame_array.size(); (void)size;
const auto index = group.index, count = group.count;
fm_assert(index < size && index <= index + count && index + count <= size);
return { &_frame_array[index], count };
}
auto wall_atlas::group(size_t dir, Tag tag) const -> const Group*
{
fm_assert(tag < Tag::COUNT);
const auto* const set_ = direction(dir);
if (!set_)
return {};
const auto& set = *set_;
const auto memfn = set.members[(size_t)tag].member;
const Group& ret = set.*memfn;
if (ret.is_empty())
return {};
return &ret;
}
auto wall_atlas::group(const Direction& dir, Tag tag) const -> const Group*
{
fm_assert(tag < Tag::COUNT);
const auto memfn = dir.members[(size_t)tag].member;
const Group& ret = dir.*memfn;
if (ret.is_empty())
return {};
return &ret;
}
auto wall_atlas::group(const Direction* dir, Tag tag) const -> const Group*
{
fm_debug_assert(dir != nullptr);
return group(*dir, tag);
}
auto wall_atlas::direction(size_t dir) const -> const Direction*
{
return get_Direction(Direction_(dir));
}
uint8_t wall_atlas::direction_count() const { return (uint8_t)_dir_array.size(); }
auto wall_atlas::raw_frame_array() const -> ArrayView<const Frame> { return _frame_array; }
StringView wall_atlas::name() const { return _info.name; }
size_t wall_atlas::enum_to_index(enum rotation r)
{
static_assert(rotation_COUNT == rotation{8});
fm_debug_assert(r < rotation_COUNT);
auto x = uint8_t(r);
x >>= 1;
return x;
}
} // namespace floormat
namespace floormat::Wall {
bool Direction::is_empty() const noexcept
{
for (auto [str, member, tag] : Direction::members)
if (const auto& val = this->*member; !val.is_empty())
return false;
return true;
}
} // namespace floormat::Wall
|