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
34 public:
36 struct HintId {
37 std::string name;
38 [[nodiscard]] auto operator<=>(const HintId &) const = default;
39 [[nodiscard]] bool operator==(const HintId &) const = default;
40 };
41
46 public:
47 static constexpr std::size_t max_index = 15;
48
49 explicit PrefilledPaletteId(std::size_t index) : index_{index}
50 {
51 if (index > max_index) {
52 panic(
53 "PrefilledPaletteId index out of range: " + std::to_string(index) + " > " +
54 std::to_string(max_index));
55 }
56 }
57
58 [[nodiscard]] std::size_t index() const
59 {
60 return index_;
61 }
62
63 [[nodiscard]] auto operator<=>(const PrefilledPaletteId &) const = default;
64 [[nodiscard]] bool operator==(const PrefilledPaletteId &) const = default;
65
66 private:
67 std::size_t index_;
68 };
69
71 struct AnimId {
72 std::string name;
73 std::size_t subtile_index;
74 [[nodiscard]] auto operator<=>(const AnimId &) const = default;
75 [[nodiscard]] bool operator==(const AnimId &) const = default;
76 };
77
79 struct RegularId {
80 std::size_t index;
81 [[nodiscard]] auto operator<=>(const RegularId &) const = default;
82 [[nodiscard]] bool operator==(const RegularId &) const = default;
83 };
84
91 std::size_t tile_index;
92 std::size_t palette_index;
93 [[nodiscard]] auto operator<=>(const PrimaryTileId &) const = default;
94 [[nodiscard]] bool operator==(const PrimaryTileId &) const = default;
95 };
96
101 using Id = std::variant<HintId, PrefilledPaletteId, RegularId, AnimId, PrimaryTileId>;
102
108
114
120
126
132
142
143 [[nodiscard]] const Id &id() const
144 {
145 return id_;
146 }
147
148 // @pre: is_hint() must be true
149 [[nodiscard]] const std::string &hint_name() const;
150
151 // @pre: is_prefilled_palette() must be true
152 [[nodiscard]] std::size_t prefilled_index() const;
153
154 // @pre: is_regular() must be true
155 [[nodiscard]] std::size_t regular_index() const;
156
157 [[nodiscard]] bool is_hint() const
158 {
159 return std::holds_alternative<HintId>(id_);
160 }
161
162 [[nodiscard]] bool is_prefilled_palette() const
163 {
164 return std::holds_alternative<PrefilledPaletteId>(id_);
165 }
166
167 [[nodiscard]] bool is_regular() const
168 {
169 return std::holds_alternative<RegularId>(id_);
170 }
171
172 [[nodiscard]] const ColorSet &color_set() const
173 {
174 return color_set_;
175 }
176
177 [[nodiscard]] std::size_t color_count() const;
178
187 [[nodiscard]] auto operator<=>(const PackableTile &other) const
188 {
189 return id_ <=> other.id_;
190 }
191
196 [[nodiscard]] bool operator==(const PackableTile &other) const
197 {
198 return id_ == other.id_;
199 }
200
201 private:
202 Id id_;
203 ColorSet color_set_;
204};
205
206inline std::string to_string(const PackableTile::Id &id)
207{
208 return std::visit(
209 []<typename IdVariant>(const IdVariant &value) -> std::string {
210 using T = std::decay_t<IdVariant>;
211 if constexpr (std::is_same_v<T, PackableTile::HintId>) {
212 return "Hint(" + value.name + ")";
213 }
214 else if constexpr (std::is_same_v<T, PackableTile::PrefilledPaletteId>) {
215 return "Prefilled(" + std::to_string(value.index()) + ")";
216 }
217 else if constexpr (std::is_same_v<T, PackableTile::RegularId>) {
218 return "Regular(" + std::to_string(value.index) + ")";
219 }
220 else if constexpr (std::is_same_v<T, PackableTile::AnimId>) {
221 return "Anim(" + value.name + ", " + std::to_string(value.subtile_index) + ")";
222 }
223 else if constexpr (std::is_same_v<T, PackableTile::PrimaryTileId>) {
224 return "Primary(tile=" + std::to_string(value.tile_index) +
225 ", palette=" + std::to_string(value.palette_index) + ")";
226 }
227 else {
228 static_assert(sizeof(T) == 0, "Unhandled PackableTile::Id variant alternative");
229 panic("Unhandled PackableTile::Id variant alternative");
230 }
231 },
232 id);
233}
234
235} // namespace porytiles
236
237// Hash specializations for Id types (enables std::hash<PackableTile::Id>)
238template <>
239struct std::hash<porytiles::PackableTile::HintId> {
240 std::size_t operator()(const porytiles::PackableTile::HintId &id) const noexcept
241 {
242 return std::hash<std::string>{}(id.name);
243 }
244};
245
246template <>
247struct std::hash<porytiles::PackableTile::PrefilledPaletteId> {
248 std::size_t operator()(const porytiles::PackableTile::PrefilledPaletteId &id) const noexcept
249 {
250 return std::hash<std::size_t>{}(id.index());
251 }
252};
253
254template <>
255struct std::hash<porytiles::PackableTile::RegularId> {
256 std::size_t operator()(const porytiles::PackableTile::RegularId &id) const noexcept
257 {
258 return std::hash<std::size_t>{}(id.index);
259 }
260};
261
262template <>
263struct std::hash<porytiles::PackableTile::AnimId> {
264 std::size_t operator()(const porytiles::PackableTile::AnimId &id) const noexcept
265 {
266 // Hash combining via Boost's hash_combine formula: the magic constant 0x9e3779b9 is the golden ratio's
267 // fractional part scaled to 32 bits, and the bit shifts spread bits to avoid collisions
268 std::size_t seed = std::hash<std::string>{}(id.name);
269 seed ^= std::hash<std::size_t>{}(id.subtile_index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
270 return seed;
271 }
272};
273
274template <>
275struct std::hash<porytiles::PackableTile::PrimaryTileId> {
276 std::size_t operator()(const porytiles::PackableTile::PrimaryTileId &id) const noexcept
277 {
278 std::size_t seed = std::hash<std::size_t>{}(id.tile_index);
279 seed ^= std::hash<std::size_t>{}(id.palette_index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
280 return seed;
281 }
282};
A set of colors represented as a bitset.
Definition color_set.hpp:22
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