summaryrefslogtreecommitdiffhomepage
path: root/main/editor.cpp
blob: 58b1e14a3184cc5437b4cdbafa246d43e229acbd (plain)
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