summaryrefslogtreecommitdiffhomepage
path: root/src/wall-atlas.hpp
blob: df5c7debfc08ab40b4cdf56b445ad61cce115531 (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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#pragma once
#include "compat/defs.hpp"
#include "src/rotation.hpp"
#include "src/pass-mode.hpp"
#include "wall-defs.hpp"
#include <array>
#include <bitset>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/String.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Math/Color.h>
#include <Magnum/GL/Texture.h>

namespace floormat { class wall_atlas; }

namespace floormat::Wall {

uint8_t direction_index_from_name(StringView s) noexcept(false);
StringView direction_index_to_name(size_t i) noexcept(false);

struct Frame
{
    Vector2ui offset = { (unsigned)-1, (unsigned)-1 }, size;

    bool operator==(const Frame&) const noexcept;
};

struct Group
{
    uint32_t index = (uint32_t)-1, count = 0;
    Vector2ui pixel_size;
    Color4 tint_mult{1,1,1,1};
    uint8_t from_rotation = (uint8_t)-1;
    bool mirrored     : 1 = false,
         default_tint : 1 = true,
         is_defined   : 1 = false;

    //bool is_empty() const noexcept { return count == 0; }

    bool operator==(const Group&) const noexcept;
};

struct Direction
{
    using memfn_ptr = Group Direction::*;
    struct member_tuple { StringView name; memfn_ptr member; Group_ tag; };

    Group wall{}, side{}, top{}, corner{};

    const Group& group(Group_ i) const;
    const Group& group(size_t i) const;
    Group& group(Group_ i);
    Group& group(size_t i);

    bool operator==(const Direction&) const noexcept;

    static constexpr inline member_tuple groups[] = {
        { "wall"_s,     &Direction::wall,     Group_::wall      },
        { "side"_s,     &Direction::side,     Group_::side      },
        { "top"_s,      &Direction::top,      Group_::top       },
        { "corner"_s,   &Direction::corner,   Group_::corner    },
    };
    static_assert(std::size(groups) == (size_t)Group_::COUNT);

    static constexpr inline member_tuple groups_for_draw[] = {
        { "wall"_s,     &Direction::wall,     Group_::wall      },
        { "side"_s,     &Direction::side,     Group_::side      },
        { "top"_s,      &Direction::top,      Group_::top       },
    };
};

struct Info
{
    String name;
    unsigned depth = 0;
    pass_mode passability = pass_mode::blocked;

    bool operator==(const Info&) const noexcept;
};

struct DirArrayIndex {
    uint8_t val = (uint8_t)-1;
    explicit operator bool() const { return val != (uint8_t)-1; }

    bool operator==(const DirArrayIndex&) const noexcept;
};

void resolve_wall_rotations(Array<Wall::Direction>& dirs, const std::array<DirArrayIndex, Direction_COUNT>& map) noexcept(false);

} // namespace floormat::Wall

namespace floormat {

struct wall_atlas_def final
{
    bool operator==(const wall_atlas_def&) const noexcept;

    Wall::Info header;
    Array<Wall::Frame> frames;
    Array<Wall::Direction> direction_array;
    std::array<Wall::DirArrayIndex, Wall::Direction_COUNT> direction_map;
    std::bitset<Wall::Direction_COUNT> direction_mask{0};

    static wall_atlas_def deserialize(StringView filename);
    void serialize(StringView filename) const;
    static void serialize(StringView filename, const Wall::Info& header, ArrayView<const Wall::Frame> frames,
                          ArrayView<const Wall::Direction> dir_array,
                          std::array<Wall::DirArrayIndex, Wall::Direction_COUNT> dir_map);
};

class wall_atlas final
{
    using Frame = Wall::Frame;
    using Group = Wall::Group;
    using Direction_ = Wall::Direction_;
    using Direction = Wall::Direction;
    using Info = Wall::Info;
    using Group_ = Wall::Group_;
    using DirArrayIndex = Wall::DirArrayIndex;

    Array<Direction> _dir_array;
    Array<Frame> _frame_array;
    Info _info;
    String _path;
    Vector2ui _image_size;
    GL::Texture2D _texture;
    std::array<DirArrayIndex, Wall::Direction_COUNT> _direction_map;

    Direction* get_Direction(Direction_ num) const;

public:
    fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(wall_atlas);
    wall_atlas() noexcept;
    ~wall_atlas() noexcept;
    wall_atlas(wall_atlas_def def, String path, const ImageView2D& img);
    void serialize(StringView filename) const;

    const Group* group(Direction_ dir, Group_ group) const;
    const Group* group(size_t dir, size_t group) const;
    const Group* group(size_t dir, Group_ tag) const;
    const Group* group(const Direction& dir, Group_ group) const;
    const Direction* direction(size_t dir) const;
    const Direction* direction(Direction_ dir) const;
    const Direction& calc_direction(Direction_ dir) const;
    uint8_t direction_count() const;
    ArrayView<const Frame> frames(const Group& a) const;
    ArrayView<const Frame> frames(Direction_ dir, Group_ g) const noexcept(false);
    ArrayView<const Frame> raw_frame_array() const;

    unsigned depth() const { return _info.depth; } // todo use it in more places
    const Info& info() const { return _info; }
    StringView name() const { return _info.name; }
    //StringView path() const { return _path; }

    GL::Texture2D& texture();
    Vector2ui image_size() const;

    static size_t enum_to_index(enum rotation x);
    static Vector2ui expected_size(unsigned depth, Group_ group);

    struct dir_tuple
    {
        StringView name;
        Direction_ direction;
    };

    static constexpr dir_tuple directions[] = {
        { "n"_s, Direction_::N },
        { "w"_s, Direction_::W },
    };
};

} // namespace floormat