Porytiles
Loading...
Searching...
No Matches
pixel_tile.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <set>
6
9
10namespace porytiles2 {
11
12namespace tile {
13
14inline constexpr std::size_t side_length_pix = 8;
15inline constexpr std::size_t size_pix = side_length_pix * side_length_pix;
16
27[[nodiscard]] constexpr std::pair<std::size_t, std::size_t> index_to_row_col(std::size_t index)
28{
29 return {index / side_length_pix, index % side_length_pix};
30}
31
43[[nodiscard]] constexpr std::size_t row_col_to_index(std::size_t row, std::size_t col)
44{
45 return row * side_length_pix + col;
46}
47
48} // namespace tile
49
82template <SupportsTransparency PixelType>
83class PixelTile {
84 public:
85 virtual ~PixelTile() = default;
86
87 PixelTile() : pix_{} {}
88
89 explicit PixelTile(std::array<PixelType, tile::size_pix> pix) : pix_{std::move(pix)} {}
90
91 auto operator<=>(const PixelTile &) const = default;
92
102 [[nodiscard]] bool is_transparent() const
103 requires requires(const PixelType &p) { p.is_transparent(); }
104 {
105 return is_transparent_impl([](const PixelType &pixel) { return pixel.is_transparent(); });
106 }
107
119 [[nodiscard]] bool is_transparent(const PixelType &extrinsic) const
120 requires requires(const PixelType &p) { p.is_transparent(p); }
121 {
122 return is_transparent_impl([&extrinsic](const PixelType &pixel) { return pixel.is_transparent(extrinsic); });
123 }
124
146 [[nodiscard]] bool equals_ignoring_transparency(const PixelTile &other) const
147 requires requires(const PixelType &p) { p.is_transparent(); }
148 {
149 return equals_ignoring_transparency_impl(other, [](const PixelType &pixel) { return pixel.is_transparent(); });
150 }
151
174 [[nodiscard]] bool equals_ignoring_transparency(const PixelTile &other, const PixelType &extrinsic) const
175 requires requires(const PixelType &p) { p.is_transparent(p); }
176 {
177 return equals_ignoring_transparency_impl(
178 other, [&extrinsic](const PixelType &pixel) { return pixel.is_transparent(extrinsic); });
179 }
180
181 [[nodiscard]] PixelType at(std::size_t i) const
182 {
183 if (i >= tile::size_pix) {
184 panic("index out of bounds: " + std::to_string(i));
185 }
186 return pix_[i];
187 }
188
189 [[nodiscard]] PixelType at(std::size_t row, std::size_t col) const
190 {
191 if (row >= tile::side_length_pix) {
192 panic("row index out of bounds: " + std::to_string(row));
193 }
194 if (col >= tile::side_length_pix) {
195 panic("col index out of bounds: " + std::to_string(col));
196 }
197 return pix_[row * tile::side_length_pix + col];
198 }
199
200 void set(std::size_t i, const PixelType &p)
201 {
202 if (i >= tile::size_pix) {
203 panic("index out of bounds: " + std::to_string(i));
204 }
205 pix_[i] = p;
206 }
207
208 void set(std::size_t row, std::size_t col, const PixelType &p)
209 {
210 if (row >= tile::side_length_pix) {
211 panic("row index out of bounds: " + std::to_string(row));
212 }
213 if (col >= tile::side_length_pix) {
214 panic("col index out of bounds: " + std::to_string(col));
215 }
216 pix_[row * tile::side_length_pix + col] = p;
217 }
218
230 [[nodiscard]] PixelTile flip(bool h_flip, bool v_flip) const
231 {
232 PixelTile flipped_tile{};
233 for (std::size_t row = 0; row < tile::side_length_pix; ++row) {
234 for (std::size_t col = 0; col < tile::side_length_pix; ++col) {
235 const std::size_t src_row = v_flip ? (tile::side_length_pix - 1 - row) : row;
236 const std::size_t src_col = h_flip ? (tile::side_length_pix - 1 - col) : col;
237 flipped_tile.set(row, col, at(src_row, src_col));
238 }
239 }
240 return flipped_tile;
241 }
242
257 [[nodiscard]] std::set<PixelType> unique_nontransparent_colors() const
258 requires requires(const PixelType &p) { p.is_transparent(); }
259 {
260 return unique_nontransparent_colors_impl([](const PixelType &pixel) { return pixel.is_transparent(); });
261 }
262
281 [[nodiscard]] std::set<PixelType> unique_nontransparent_colors(const PixelType &extrinsic) const
282 requires requires(const PixelType &p) { p.is_transparent(p); }
283 {
284 return unique_nontransparent_colors_impl(
285 [&extrinsic](const PixelType &pixel) { return pixel.is_transparent(extrinsic); });
286 }
287
288 [[nodiscard]] const std::array<PixelType, tile::size_pix> &pix() const
289 {
290 return pix_;
291 }
292
293 private:
306 template <typename TransparencyPredicate>
307 [[nodiscard]] bool is_transparent_impl(TransparencyPredicate is_transparent_pred) const
308 {
309 return std::ranges::all_of(pix(), is_transparent_pred);
310 }
311
325 template <typename TransparencyPredicate>
326 [[nodiscard]] bool
327 equals_ignoring_transparency_impl(const PixelTile &other, TransparencyPredicate is_transparent_pred) const
328 {
329 for (std::size_t i = 0; i < tile::size_pix; ++i) {
330 const auto &pixel1 = pix_.at(i);
331 const auto &pixel2 = other.pix_.at(i);
332
333 if (is_transparent_pred(pixel1) && is_transparent_pred(pixel2)) {
334 continue; // Both transparent, consider equal
335 }
336 if (pixel1 != pixel2) {
337 return false; // Different pixels
338 }
339 }
340 return true;
341 }
342
355 template <typename TransparencyPredicate>
356 [[nodiscard]] std::set<PixelType> unique_nontransparent_colors_impl(TransparencyPredicate is_transparent_pred) const
357 {
358 std::set<PixelType> colors;
359 for (const auto &pixel : pix_) {
360 if (!is_transparent_pred(pixel)) {
361 colors.insert(pixel);
362 }
363 }
364 return colors;
365 }
366
367 std::array<PixelType, tile::size_pix> pix_;
368};
369
370} // namespace porytiles2
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
PixelTile flip(bool h_flip, bool v_flip) const
Creates a flipped copy of this PixelTile.
virtual ~PixelTile()=default
void set(std::size_t row, std::size_t col, const PixelType &p)
PixelType at(std::size_t row, std::size_t col) const
void set(std::size_t i, const PixelType &p)
auto operator<=>(const PixelTile &) const =default
std::set< PixelType > unique_nontransparent_colors(const PixelType &extrinsic) const
Returns the set of unique non-transparent colors present in this PixelTile.
const std::array< PixelType, tile::size_pix > & pix() const
bool equals_ignoring_transparency(const PixelTile &other, const PixelType &extrinsic) const
Compares this PixelTile with another, treating all transparent pixels as equal.
PixelType at(std::size_t i) const
bool is_transparent(const PixelType &extrinsic) const
Checks if this entire PixelTile is transparent.
bool equals_ignoring_transparency(const PixelTile &other) const
Compares this PixelTile with another, treating all transparent pixels as equal.
bool is_transparent() const
Checks if this entire PixelTile is transparent (intrinsic transparency only).
std::set< PixelType > unique_nontransparent_colors() const
Returns the set of unique non-transparent colors present in this PixelTile (intrinsic transparency on...
PixelTile(std::array< PixelType, tile::size_pix > pix)
constexpr std::size_t row_col_to_index(std::size_t row, std::size_t col)
Converts row and column coordinates to a linear index.
constexpr std::size_t size_pix
constexpr std::size_t side_length_pix
constexpr std::pair< std::size_t, std::size_t > index_to_row_col(std::size_t index)
Converts a linear index to row and column coordinates.
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.hpp:53