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
131
132
133
134
135
136
137
138
139
140
141
142
|
#include "wall-atlas.hpp"
#include "compat/assert.hpp"
#include <utility>
#include <Magnum/ImageView.h>
#include <Magnum/GL/TextureFormat.h>
namespace floormat {
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 }
{
const auto frame_count = frames.size();
for (const Direction& dir : directions)
{
for (auto [_str, _group, tag] : Direction::members)
{
const auto* g = group(dir, tag);
if (!g)
continue;
fm_assert(g->count > 0 == g->index < (uint32_t)-1);
if (g->count > 0)
{
fm_assert(g->index < frame_count);
fm_assert(g->index + g->count <= frame_count);
}
}
}
_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; }
auto wall_atlas::info() const -> const Info& { return _info; }
GL::Texture2D& wall_atlas::texture() { fm_debug_assert(_texture.id()); return _texture; }
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;
}
bool Frame::operator==(const Frame&) const noexcept = default;
bool Group::operator==(const Group&) const noexcept = default;
bool Direction::operator==(const Direction&) const noexcept = default;
bool Info::operator==(const floormat::Wall::Info&) const noexcept = default;
bool DirArrayIndex::operator==(const floormat::Wall::DirArrayIndex&) const noexcept = default;
} // namespace floormat::Wall
|