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
|
#include "editor.hpp"
#include "serialize/json-helper.hpp"
#include "serialize/tile-atlas.hpp"
#include "src/loader.hpp"
#include "random.hpp"
#include "compat/assert.hpp"
#include "compat/unreachable.hpp"
#include <filesystem>
#include <vector>
namespace floormat {
static const std::filesystem::path image_path{IMAGE_PATH, std::filesystem::path::generic_format};
tile_type::tile_type(editor_mode mode, Containers::StringView name) : _name{name}, _mode{mode}
{
load_atlases();
}
void tile_type::load_atlases()
{
using atlas_array = std::vector<std::shared_ptr<tile_atlas>>;
for (auto& atlas : json_helper::from_json<atlas_array>(image_path/(_name + ".json")))
{
Containers::StringView name = atlas->name();
if (auto x = name.findLast('.'); x)
name = name.prefix(x.data());
std::get<1>(_permutation).reserve((std::size_t)atlas->num_tiles().product());
_atlases[name] = std::move(atlas);
}
}
std::shared_ptr<tile_atlas> tile_type::maybe_atlas(Containers::StringView str)
{
auto it = _atlases.find(str);
if (it == _atlases.end())
return nullptr;
else
return it->second;
}
std::shared_ptr<tile_atlas> tile_type::atlas(Containers::StringView str)
{
if (auto ptr = maybe_atlas(str); ptr)
return ptr;
else
ABORT("no such atlas: %s", str.cbegin());
}
void tile_type::clear_selection()
{
_selected_tile = {};
_permutation = {};
_selection_mode = sel_none;
}
void tile_type::select_tile(const std::shared_ptr<tile_atlas>& atlas, std::uint8_t variant)
{
ASSERT(atlas);
clear_selection();
_selection_mode = sel_tile;
_selected_tile = { atlas, variant };
}
void tile_type::select_tile_permutation(const std::shared_ptr<tile_atlas>& atlas)
{
ASSERT(atlas);
clear_selection();
_selection_mode = sel_perm;
_permutation = { atlas, {} };
}
bool tile_type::is_tile_selected(const std::shared_ptr<tile_atlas>& atlas, std::uint8_t variant)
{
ASSERT(atlas);
return _selection_mode == sel_tile && _selected_tile == std::make_tuple(atlas, variant);
}
bool tile_type::is_permutation_selected(const std::shared_ptr<tile_atlas>& atlas)
{
ASSERT(atlas);
return _selection_mode == sel_perm && std::get<0>(_permutation) == atlas;
}
template<std::random_access_iterator T>
void fisher_yates(T begin, T end)
{
const auto N = std::distance(begin, end);
for (auto i = N-1; i >= 1; i--)
{
const auto j = random(i+1);
using std::swap;
swap(begin[i], begin[j]);
}
}
std::tuple<std::shared_ptr<tile_atlas>, std::uint8_t> tile_type::get_selected_perm()
{
auto& [atlas, vec] = _permutation;
const std::size_t N = atlas->num_tiles().product();
if (N == 0)
return {};
if (vec.empty())
{
for (std::uint8_t i = 0; i < N; i++)
vec.push_back(i);
fisher_yates(vec.begin(), vec.end());
}
const auto idx = vec.back();
vec.pop_back();
return {atlas, idx};
}
std::optional<std::tuple<std::shared_ptr<tile_atlas>, std::uint8_t>> tile_type::get_selected()
{
switch (_selection_mode)
{
case sel_none: return std::nullopt;
case sel_tile: return _selected_tile;
case sel_perm: return get_selected_perm();
default: unreachable();
}
}
editor_state::editor_state()
{
}
} // namespace floormat
|