Porytiles
Loading...
Searching...
No Matches
packable_tile.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <compare>
4#include <cstddef>
5#include <string>
6#include <variant>
7
10
11namespace porytiles {
12
36 public:
40 struct HintId {
41 std::string name;
42 [[nodiscard]] auto operator<=>(const HintId &) const = default;
43 [[nodiscard]] bool operator==(const HintId &) const = default;
44 };
45
52 public:
53 static constexpr std::size_t max_index = 15;
54
55 explicit PrefilledPaletteId(std::size_t index) : index_{index}
56 {
57 if (index > max_index) {
58 panic(
59 "PrefilledPaletteId index out of range: " + std::to_string(index) + " > " +
60 std::to_string(max_index));
61 }
62 }
63
64 [[nodiscard]] std::size_t index() const
65 {
66 return index_;
67 }
68
69 [[nodiscard]] auto operator<=>(const PrefilledPaletteId &) const = default;
70 [[nodiscard]] bool operator==(const PrefilledPaletteId &) const = default;
71
72 private:
73 std::size_t index_;
74 };
75
79 struct AnimId {
80 std::string name;
81 std::size_t subtile_index;
82 [[nodiscard]] auto operator<=>(const AnimId &) const = default;
83 [[nodiscard]] bool operator==(const AnimId &) const = default;
84 };
85
89 struct RegularId {
90 std::size_t index;
91 [[nodiscard]] auto operator<=>(const RegularId &) const = default;
92 [[nodiscard]] bool operator==(const RegularId &) const = default;
93 };
94
103 std::size_t tile_index;
104 std::size_t pal_index;
105 [[nodiscard]] auto operator<=>(const PrimaryTileId &) const = default;
106 [[nodiscard]] bool operator==(const PrimaryTileId &) const = default;
107 };
108
115 using Id = std::variant<HintId, PrefilledPaletteId, RegularId, AnimId, PrimaryTileId>;
116
124
132
140
148
156
168
169 [[nodiscard]] const Id &id() const
170 {
171 return id_;
172 }
173
174 // @pre: is_hint() must be true
175 [[nodiscard]] const std::string &hint_name() const;
176
177 // @pre: is_prefilled_palette() must be true
178 [[nodiscard]] std::size_t prefilled_index() const;
179
180 // @pre: is_regular() must be true
181 [[nodiscard]] std::size_t regular_index() const;
182
183 [[nodiscard]] bool is_hint() const
184 {
185 return std::holds_alternative<HintId>(id_);
186 }
187
188 [[nodiscard]] bool is_prefilled_palette() const
189 {
190 return std::holds_alternative<PrefilledPaletteId>(id_);
191 }
192
193 [[nodiscard]] bool is_regular() const
194 {
195 return std::holds_alternative<RegularId>(id_);
196 }
197
198 [[nodiscard]] const ColorSet &color_set() const
199 {
200 return color_set_;
201 }
202
203 [[nodiscard]] std::size_t color_count() const;
204
215 [[nodiscard]] auto operator<=>(const PackableTile &other) const
216 {
217 return id_ <=> other.id_;
218 }
219
226 [[nodiscard]] bool operator==(const PackableTile &other) const
227 {
228 return id_ == other.id_;
229 }
230
231 private:
232 Id id_;
233 ColorSet color_set_;
234};
235
236inline std::string to_string(const PackableTile::Id &id)
237{
238 return std::visit(
239 []<typename IdVariant>(const IdVariant &value) -> std::string {
240 using T = std::decay_t<IdVariant>;
241 if constexpr (std::is_same_v<T, PackableTile::HintId>) {
242 return "Hint(" + value.name + ")";
243 }
244 else if constexpr (std::is_same_v<T, PackableTile::PrefilledPaletteId>) {
245 return "Prefilled(" + std::to_string(value.index()) + ")";
246 }
247 else if constexpr (std::is_same_v<T, PackableTile::RegularId>) {
248 return "Regular(" + std::to_string(value.index) + ")";
249 }
250 else if constexpr (std::is_same_v<T, PackableTile::AnimId>) {
251 return "Anim(" + value.name + ", " + std::to_string(value.subtile_index) + ")";
252 }
253 else if constexpr (std::is_same_v<T, PackableTile::PrimaryTileId>) {
254 return "Primary(tile=" + std::to_string(value.tile_index) + ", pal=" + std::to_string(value.pal_index) +
255 ")";
256 }
257 else {
258 static_assert(sizeof(T) == 0, "Unhandled PackableTile::Id variant alternative");
259 panic("Unhandled PackableTile::Id variant alternative");
260 }
261 },
262 id);
263}
264
265} // namespace porytiles
266
267// Hash specializations for Id types (enables std::hash<PackableTile::Id>)
268template <>
269struct std::hash<porytiles::PackableTile::HintId> {
270 std::size_t operator()(const porytiles::PackableTile::HintId &id) const noexcept
271 {
272 return std::hash<std::string>{}(id.name);
273 }
274};
275
276template <>
277struct std::hash<porytiles::PackableTile::PrefilledPaletteId> {
278 std::size_t operator()(const porytiles::PackableTile::PrefilledPaletteId &id) const noexcept
279 {
280 return std::hash<std::size_t>{}(id.index());
281 }
282};
283
284template <>
285struct std::hash<porytiles::PackableTile::RegularId> {
286 std::size_t operator()(const porytiles::PackableTile::RegularId &id) const noexcept
287 {
288 return std::hash<std::size_t>{}(id.index);
289 }
290};
291
292template <>
293struct std::hash<porytiles::PackableTile::AnimId> {
294 std::size_t operator()(const porytiles::PackableTile::AnimId &id) const noexcept
295 {
296 // Hash combining via Boost's hash_combine formula: the magic constant 0x9e3779b9 is the golden ratio's
297 // fractional part scaled to 32 bits, and the bit shifts spread bits to avoid collisions
298 std::size_t seed = std::hash<std::string>{}(id.name);
299 seed ^= std::hash<std::size_t>{}(id.subtile_index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
300 return seed;
301 }
302};
303
304template <>
305struct std::hash<porytiles::PackableTile::PrimaryTileId> {
306 std::size_t operator()(const porytiles::PackableTile::PrimaryTileId &id) const noexcept
307 {
308 std::size_t seed = std::hash<std::size_t>{}(id.tile_index);
309 seed ^= std::hash<std::size_t>{}(id.pal_index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
310 return seed;
311 }
312};
A set of colors represented as a bitset.
Definition color_set.hpp:26
Identifies a tile created from a prefilled palette.
bool operator==(const PrefilledPaletteId &) const =default
auto operator<=>(const PrefilledPaletteId &) const =default
Wraps a ColorSet with a tile ID for tracking during palette packing.
auto operator<=>(const PackableTile &other) const
Three-way comparison operator.
std::size_t color_count() const
bool operator==(const PackableTile &other) const
Equality comparison operator.
bool is_prefilled_palette() const
std::size_t prefilled_index() const
std::size_t regular_index() const
const ColorSet & color_set() const
const Id & id() const
std::variant< HintId, PrefilledPaletteId, RegularId, AnimId, PrimaryTileId > Id
Variant type for tile identification.
const std::string & hint_name() const
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.cpp:43
std::string to_string(const PrimaryPairingMode m)
Converts a PrimaryPairingMode to its canonical string representation.
Identifies a tile created from an animation.
auto operator<=>(const AnimId &) const =default
bool operator==(const AnimId &) const =default
Identifies a tile created from a palette hint.
bool operator==(const HintId &) const =default
auto operator<=>(const HintId &) const =default
Identifies a tile reconstructed from a compiled primary tileset.
auto operator<=>(const PrimaryTileId &) const =default
bool operator==(const PrimaryTileId &) const =default
Identifies a regular input tile.
bool operator==(const RegularId &) const =default
auto operator<=>(const RegularId &) const =default
std::size_t operator()(const porytiles::PackableTile::AnimId &id) const noexcept
std::size_t operator()(const porytiles::PackableTile::HintId &id) const noexcept
std::size_t operator()(const porytiles::PackableTile::PrefilledPaletteId &id) const noexcept
std::size_t operator()(const porytiles::PackableTile::PrimaryTileId &id) const noexcept
std::size_t operator()(const porytiles::PackableTile::RegularId &id) const noexcept