Porytiles
Loading...
Searching...
No Matches
metatile.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4
8
9namespace porytiles2 {
10
11namespace metatile {
12
13inline constexpr std::size_t tiles_per_side = 2;
15inline constexpr std::size_t tiles_per_metatile = tiles_per_metatile_layer * 3;
16inline constexpr std::size_t side_length_pix = tiles_per_side * tile::side_length_pix;
17inline constexpr std::size_t entries_per_metatile_dual = 8;
18inline constexpr std::size_t entries_per_metatile_triple = 12;
19
20enum class Layer : std::uint8_t { bottom = 0, middle = 1, top = 2 };
21
22inline std::string to_string(Layer layer)
23{
24 switch (layer) {
25 case Layer::bottom:
26 return "bottom";
27 case Layer::middle:
28 return "middle";
29 case Layer::top:
30 return "top";
31 }
32 panic("unhandled Layer value");
33}
34
35enum class Subtile : std::uint8_t { northwest = 0, northeast = 1, southwest = 2, southeast = 3 };
36
37inline std::string to_string(Subtile layer)
38{
39 switch (layer) {
41 return "northwest(" + std::to_string(static_cast<std::uint8_t>(layer)) + ")";
43 return "northeast(" + std::to_string(static_cast<std::uint8_t>(layer)) + ")";
45 return "southwest(" + std::to_string(static_cast<std::uint8_t>(layer)) + ")";
47 return "southeast(" + std::to_string(static_cast<std::uint8_t>(layer)) + ")";
48 }
49 panic("unhandled Subtile value");
50}
51
52[[nodiscard]] inline std::tuple<std::size_t, Layer, Subtile> from_tile_index(std::size_t tile_index)
53{
54 const std::size_t metatile_index = tile_index / tiles_per_metatile;
55 const std::size_t local_index = tile_index % tiles_per_metatile;
56 const auto layer = static_cast<Layer>(local_index / tiles_per_metatile_layer);
57 const auto subtile = static_cast<Subtile>(local_index % tiles_per_metatile_layer);
58
59 return {metatile_index, layer, subtile};
60}
61
62[[nodiscard]] inline std::string message_header(
63 std::size_t index,
64 Layer layer,
65 Subtile subtile,
66 std::size_t subtile_row,
67 std::size_t subtile_col,
68 const TextFormatter &format)
69{
70 return format.format(
71 "{} {}|{}|{}|{},{}",
72 FormatParam{"metatile", Style::bold},
76 FormatParam{std::to_string(subtile_row), Style::bold},
77 FormatParam{std::to_string(subtile_col), Style::bold});
78}
79
80} // namespace metatile
81
94template <SupportsTransparency PixelType>
95class Metatile {
96 public:
97 Metatile() : id_{} {}
98
99 bool operator==(const Metatile &) const = default;
100
110 [[nodiscard]] bool is_transparent() const
111 requires requires(const PixelType &p) { p.is_transparent(); }
112 {
113 const bool bottom_transparent =
114 std::ranges::all_of(bottom(), [](const auto &tile) { return tile.is_transparent(); });
115 const bool middle_transparent =
116 std::ranges::all_of(middle(), [](const auto &tile) { return tile.is_transparent(); });
117 const bool top_transparent = std::ranges::all_of(top(), [](const auto &tile) { return tile.is_transparent(); });
118 return bottom_transparent && middle_transparent && top_transparent;
119 }
120
132 [[nodiscard]] bool is_transparent(const PixelType &extrinsic) const
133 requires requires(const PixelType &p) { p.is_transparent(p); }
134 {
135 const bool bottom_transparent =
136 std::ranges::all_of(bottom(), [=](const auto &tile) { return tile.is_transparent(extrinsic); });
137 const bool middle_transparent =
138 std::ranges::all_of(middle(), [=](const auto &tile) { return tile.is_transparent(extrinsic); });
139 const bool top_transparent =
140 std::ranges::all_of(top(), [=](const auto &tile) { return tile.is_transparent(extrinsic); });
141 return bottom_transparent && middle_transparent && top_transparent;
142 }
143
152 [[nodiscard]] std::array<PixelTile<PixelType>, metatile::tiles_per_metatile> decompose() const
153 {
154 std::array<PixelTile<PixelType>, metatile::tiles_per_metatile> tiles{};
155
156 auto out_it = tiles.begin();
157 out_it = std::ranges::copy(bottom(), out_it).out;
158 out_it = std::ranges::copy(middle(), out_it).out;
159 std::ranges::copy(top(), out_it);
160
161 return tiles;
162 }
163
173 [[nodiscard]] const PixelTile<PixelType> &bottom(std::size_t i) const
174 {
175 if (i > 3) {
176 panic(fmt::format("index {} out of bounds: must be [0,3]", i));
177 }
178 return bottom_[i];
179 }
180
189 [[nodiscard]] const std::array<PixelTile<PixelType>, metatile::tiles_per_metatile_layer> &bottom() const
190 {
191 return bottom_;
192 }
193
203 void set_bottom(std::size_t i, PixelTile<PixelType> tile)
204 {
205 if (i > 3) {
206 panic(fmt::format("index {} out of bounds: must be [0,3]", i));
207 }
208 bottom_[i] = std::move(tile);
209 }
210
220 [[nodiscard]] const PixelTile<PixelType> &middle(std::size_t i) const
221 {
222 if (i > 3) {
223 panic(fmt::format("index {} out of bounds: must be [0,3]", i));
224 }
225 return middle_[i];
226 }
227
236 [[nodiscard]] const std::array<PixelTile<PixelType>, metatile::tiles_per_metatile_layer> &middle() const
237 {
238 return middle_;
239 }
240
250 void set_middle(std::size_t i, PixelTile<PixelType> tile)
251 {
252 if (i > 3) {
253 panic(fmt::format("index {} out of bounds: must be [0,3]", i));
254 }
255 middle_[i] = std::move(tile);
256 }
257
267 [[nodiscard]] const PixelTile<PixelType> &top(std::size_t i) const
268 {
269 if (i > 3) {
270 panic(fmt::format("index {} out of bounds: must be [0,3]", i));
271 }
272 return top_[i];
273 }
274
283 [[nodiscard]] const std::array<PixelTile<PixelType>, metatile::tiles_per_metatile_layer> &top() const
284 {
285 return top_;
286 }
287
297 void set_top(std::size_t i, PixelTile<PixelType> tile)
298 {
299 if (i > 3) {
300 panic(fmt::format("index {} out of bounds: must be [0,3]", i));
301 }
302 top_[i] = std::move(tile);
303 }
304
305 private:
306 std::array<PixelTile<PixelType>, metatile::tiles_per_metatile_layer> bottom_;
307 std::array<PixelTile<PixelType>, metatile::tiles_per_metatile_layer> middle_;
308 std::array<PixelTile<PixelType>, metatile::tiles_per_metatile_layer> top_;
309 unsigned int id_;
310};
311
312namespace metatile {
313
314template <typename T>
315[[nodiscard]] std::vector<PixelTile<T>> decompose(const std::vector<Metatile<T>> &metatiles)
316{
317 std::vector<PixelTile<T>> tiles;
318 tiles.reserve(metatiles.size() * tiles_per_metatile);
319 for (const auto &mt : metatiles) {
320 tiles.append_range(mt.decompose());
321 }
322 return tiles;
323
324 // This is a less performant version that uses std::ranges
325 //
326 // auto tiles = metatiles
327 // | std::views::transform([](const auto& mt) { return mt.decompose(); })
328 // | std::views::join
329 // | std::ranges::to<std::vector>();
330 //
331 // This transforms each Metatile to a vector<Tile>, flattens (joins) all the vectors together, and collects into a
332 // final vector<Tile>.
333}
334
335} // namespace metatile
336
337} // namespace porytiles2
A text parameter with associated styling for formatted output.
The core tileset entity - a 2x2 grid of PixelTile objects arranged into three layers.
Definition metatile.hpp:95
const PixelTile< PixelType > & top(std::size_t i) const
Get a constant reference to a PixelTile from the top layer.
Definition metatile.hpp:267
const PixelTile< PixelType > & middle(std::size_t i) const
Get a constant reference to a PixelTile from the middle layer.
Definition metatile.hpp:220
const std::array< PixelTile< PixelType >, metatile::tiles_per_metatile_layer > & top() const
Get a constant reference to the entire top layer array.
Definition metatile.hpp:283
const std::array< PixelTile< PixelType >, metatile::tiles_per_metatile_layer > & middle() const
Get a constant reference to the entire middle layer array.
Definition metatile.hpp:236
void set_middle(std::size_t i, PixelTile< PixelType > tile)
Set a PixelTile in the middle layer.
Definition metatile.hpp:250
void set_top(std::size_t i, PixelTile< PixelType > tile)
Set a Tile in the top layer.
Definition metatile.hpp:297
std::array< PixelTile< PixelType >, metatile::tiles_per_metatile > decompose() const
Decomposes this metatile into an array of PixelTiles in metatile order.
Definition metatile.hpp:152
const PixelTile< PixelType > & bottom(std::size_t i) const
Get a constant reference to a PixelTile from the bottom layer.
Definition metatile.hpp:173
bool is_transparent() const
Checks if this entire metatile is transparent (intrinsic transparency only).
Definition metatile.hpp:110
const std::array< PixelTile< PixelType >, metatile::tiles_per_metatile_layer > & bottom() const
Get a constant reference to the entire bottom layer array.
Definition metatile.hpp:189
bool operator==(const Metatile &) const =default
bool is_transparent(const PixelType &extrinsic) const
Checks if this entire metatile is transparent.
Definition metatile.hpp:132
void set_bottom(std::size_t i, PixelTile< PixelType > tile)
Set a PixelTile in the bottom layer.
Definition metatile.hpp:203
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
Abstract base class for applying text styling with context-aware formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > &params) const
Formats a string with styled parameters using fmtlib syntax.
std::string message_header(std::size_t index, Layer layer, Subtile subtile, std::size_t subtile_row, std::size_t subtile_col, const TextFormatter &format)
Definition metatile.hpp:62
std::string to_string(Layer layer)
Definition metatile.hpp:22
constexpr std::size_t tiles_per_metatile_layer
Definition metatile.hpp:14
constexpr std::size_t entries_per_metatile_dual
Definition metatile.hpp:17
constexpr std::size_t entries_per_metatile_triple
Definition metatile.hpp:18
constexpr std::size_t side_length_pix
Definition metatile.hpp:16
constexpr std::size_t tiles_per_side
Definition metatile.hpp:13
constexpr std::size_t tiles_per_metatile
Definition metatile.hpp:15
std::tuple< std::size_t, Layer, Subtile > from_tile_index(std::size_t tile_index)
Definition metatile.hpp:52
constexpr std::size_t side_length_pix
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.hpp:53
@ bold
Bold text formatting.