summaryrefslogtreecommitdiffhomepage
path: root/tile.hpp
blob: f47f90770f05c78a90a2f22952412f59ce9a5a06 (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
#pragma once
#include "loader.hpp"
#include "atlas.hpp"
#include "hash.hpp"
#include "defs.hpp"

#include <cstddef>
#include <tuple>
#include <array>
#include <memory>
#include <unordered_map>
#include <utility>

namespace Magnum::Examples {

struct tile_image final : std::tuple<atlas_ptr, UnsignedByte>
{
    constexpr int variant() const noexcept { return std::get<1>(*this); }
    atlas_ptr atlas() const noexcept { return std::get<0>(*this); }
};

struct tile final
{
    enum class pass_mode : std::uint8_t { pass_blocked, pass_yes, pass_shoot_through, pass_obscured };
    using enum pass_mode;

    tile_image ground_image_;
    pass_mode passability_ = pass_obscured;

    explicit operator bool() const noexcept { return !!std::get<0>(ground_image_); }
};

struct local_coords final : std::pair<UnsignedByte, UnsignedByte> {
    constexpr std::size_t to_index() const noexcept;
};

struct chunk_coords final : std::pair<Short, Short> {
    constexpr std::size_t to_index() const noexcept;
};

struct global_coords final : std::pair<chunk_coords, local_coords> {};

struct chunk final
{
    static constexpr std::size_t N = 16;
    static constexpr std::size_t TILE_COUNT = N*N;
    using tile_index_type = std::array<UnsignedByte, TILE_COUNT>;
    static tile_index_type make_tile_indices() noexcept;

    tile_index_type indices = make_tile_indices();

    constexpr struct tile& tile(local_coords xy);
    constexpr struct tile& tile(local_coords xy) const { return const_cast<chunk&>(*this).tile(xy); }
    constexpr struct tile& operator[](std::size_t i);

    template<typename F> constexpr inline void foreach_tile(F&& fun) { foreach_tile_<F, chunk&>(fun); }
    template<typename F> constexpr inline void foreach_tile(F&& fun) const { foreach_tile_<F, const chunk&>(fun); }

private:
    template<typename F, typename Self> constexpr void foreach_tile_(F&& fun);
    std::array<struct tile, TILE_COUNT> tiles = {};
};

constexpr std::size_t local_coords::to_index() const noexcept {
    return second*chunk::N + first;
}

constexpr struct tile& chunk::operator[](std::size_t i) {
    if (i >= TILE_COUNT)
        throw OUT_OF_RANGE(i, 0, TILE_COUNT);
    return tiles[i];
}

constexpr tile& chunk::tile(local_coords xy)
{
    auto idx = xy.to_index();
    if (idx >= TILE_COUNT)
        throw OUT_OF_RANGE(idx, 0, TILE_COUNT);
    return tiles[idx];
}

template<typename F, typename Self>
constexpr void chunk::foreach_tile_(F&& fun)
{
    for (unsigned j = 0; j < N; j++)
        for (unsigned i = 0; i < N; i++)
        {
            unsigned idx = j*N + i;
            if (tiles[idx])
                fun(*static_cast<Self>(*this).tiles[idx]);
        }
}

constexpr std::size_t chunk_coords::to_index() const noexcept
{
    using unsigned_type = std::make_unsigned_t<decltype(second)>;
    using limits = std::numeric_limits<unsigned_type>;
    constexpr auto N = limits::max() + std::size_t{1};
    static_assert(sizeof(unsigned_type) <= sizeof(std::size_t)/2);
    return (std::size_t)(unsigned_type)second * N + (std::size_t)(unsigned_type)first;
}

struct hash_chunk final {
    constexpr std::size_t operator()(chunk_coords xy) const noexcept {
        return hash<sizeof(std::size_t)*8>{}(xy.to_index());
    }
};

struct world final
{
    explicit world();

private:
    std::unordered_map<chunk_coords, std::shared_ptr<chunk>, hash_chunk> chunks;
};

} //namespace Magnum::Examples