Porytiles
Loading...
Searching...
No Matches
tile_converters.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <map>
4
14
15namespace porytiles {
16
17namespace details {
18
33template <SupportsTransparency PixelType, typename TransparencyPredicate>
35 const PixelTile<PixelType> &pixel_tile,
36 const ColorIndexMap<PixelType> &color_index_map,
37 TransparencyPredicate is_transparent_pred)
38{
39 // Map from color index to ShapeMask
40 std::map<ColorIndex, ShapeMask> index_to_mask;
41
42 // Iterate through all pixels
43 for (std::size_t row = 0; row < tile::side_length_pix; ++row) {
44 for (std::size_t col = 0; col < tile::side_length_pix; ++col) {
45 const auto pixel = pixel_tile.at(row, col);
46
47 // Skip transparent pixels
48 if (is_transparent_pred(pixel)) {
49 continue;
50 }
51
52 // Look up the color index
53 auto index_opt = color_index_map.index_at_color(pixel);
54 if (!index_opt) {
55 panic("Pixel not found in ColorIndexMap");
56 }
57
58 const ColorIndex &index = *index_opt;
59
60 // Create mask if it doesn't exist
61 if (index_to_mask.find(index) == index_to_mask.end()) {
62 index_to_mask[index] = ShapeMask{};
63 }
64
65 // Set the bit for this position
66 index_to_mask[index].set(row, col);
67 }
68 }
69
70 // Build the result ShapeTile
72 for (const auto &[index, mask] : index_to_mask) {
73 result.set(mask, index);
74 }
75
76 return result;
77}
78
101template <SupportsTransparency ColorType, std::size_t N = 0, typename TransparencyPredicate>
103 const PixelTile<ColorType> &tile, const Palette<ColorType, N> &palette, TransparencyPredicate is_transparent_pred)
104{
105 // Build a color-to-index map for efficient lookup
106 // Note: palette.color_to_index_map() returns PaletteIndex, convert to std::size_t
107 std::map<ColorType, std::size_t> color_to_index;
108 for (const auto &[color, palette_idx] : palette.color_to_index_map()) {
109 color_to_index[color] = palette_idx.value();
110 }
111
112 // Convert each pixel
113 std::array<IndexPixel, tile::size_pix> index_pixels;
114
115 for (std::size_t i = 0; i < tile::size_pix; ++i) {
116 const auto &pixel = tile.at(i);
117
118 if (is_transparent_pred(pixel)) {
119 // Transparent pixels map to index 0
120 index_pixels[i] = IndexPixel{0};
121 }
122 else {
123 // Non-transparent pixel requires a non-empty palette
124 if (palette.size() == 0) {
125 panic("non-transparent pixel found but palette is empty");
126 }
127
128 // Look up the color in the palette
129 auto it = color_to_index.find(pixel);
130 if (it != color_to_index.end()) {
131 index_pixels[i] = IndexPixel{it->second};
132 }
133 else {
134 panic("color not found in palette");
135 }
136 }
137 }
138
139 return PixelTile{index_pixels};
140}
141
162template <SupportsTransparency ColorType, std::size_t N = 0>
164 const PixelTile<IndexPixel> &index_tile, const Palette<ColorType, N> &palette, const ColorType &transparent_color)
165{
166 if (palette.size() == 0) {
167 panic("palette is empty");
168 }
169
170 const auto index_to_color = palette.index_to_color_map();
171 std::array<ColorType, tile::size_pix> color_pixels;
172
173 for (std::size_t i = 0; i < tile::size_pix; ++i) {
174 const auto &index_pixel = index_tile.at(i);
175 // Use color_index() to extract the lower 4 bits, which is the actual palette color index.
176 // This is critical for true-color mode where the full 8-bit value encodes both palette index (upper 4 bits)
177 // and color index (lower 4 bits). For standard 4-bit pixels, color_index() == index().
178 const std::size_t color_index = index_pixel.color_index();
179
180 if (color_index == 0) {
181 // Color index 0 is the transparent slot
182 color_pixels[i] = transparent_color;
183 }
184 else {
185 // Look up in index-to-color map for non-zero indices
186 auto it = index_to_color.find(PaletteIndex{color_index});
187 if (it == index_to_color.end()) {
188 panic(
189 "color_index " + std::to_string(color_index) + " out of palette bounds [0, " +
190 std::to_string(palette.size()) + ")");
191 }
192 color_pixels[i] = it->second;
193 }
194 }
195
196 return PixelTile<ColorType>{color_pixels};
197}
198
199} // namespace details
200
223template <SupportsTransparency PixelType>
224[[nodiscard]] ShapeTile<ColorIndex>
225from_pixel_tile(const PixelTile<PixelType> &pixel_tile, const ColorIndexMap<PixelType> &color_index_map)
226 requires requires(const PixelType &p) { p.is_transparent(); }
227{
229 pixel_tile, color_index_map, [](const PixelType &p) { return p.is_transparent(); });
230}
231
256template <SupportsTransparency PixelType>
258 const PixelTile<PixelType> &pixel_tile, const ColorIndexMap<PixelType> &color_index_map, const PixelType &extrinsic)
259 requires requires(const PixelType &p) { p.is_transparent(p); }
260{
262 pixel_tile, color_index_map, [&extrinsic](const PixelType &p) { return p.is_transparent(extrinsic); });
263}
264
286template <SupportsTransparency PixelType>
287[[nodiscard]] PixelTile<PixelType>
288from_shape_tile(const ShapeTile<ColorIndex> &shape_tile, const ColorIndexMap<PixelType> &color_index_map)
289{
290 // Start with a default (transparent) PixelTile
292
293 // Track which pixels have been set to detect overlaps
294 std::array<bool, tile::size_pix> pixel_set{};
295
296 // Iterate through each (ShapeMask, ColorIndex) pair
297 for (const auto &[mask, index] : shape_tile.colors()) {
298 // Look up the actual color from the ColorIndexMap
299 auto color_opt = color_index_map.color_at_index(index);
300 if (!color_opt) {
301 panic("ColorIndex not found in ColorIndexMap");
302 }
303
304 const PixelType &color = *color_opt;
305
306 // Set all pixels marked by this ShapeMask
307 for (std::size_t row = 0; row < tile::side_length_pix; ++row) {
308 for (std::size_t col = 0; col < tile::side_length_pix; ++col) {
309 if (mask.get(row, col)) {
310 std::size_t pixel_index = row * tile::side_length_pix + col;
311
312 // Check for overlap
313 if (pixel_set[pixel_index]) {
314 panic("Overlapping masks detected in ShapeTile - programmer error");
315 }
316
317 result.set(row, col, color);
318 pixel_set[pixel_index] = true;
319 }
320 }
321 }
322 }
323
324 return result;
325}
326
347template <SupportsTransparency PixelType>
348[[nodiscard]] ShapeTile<PixelType>
350{
352
353 // Iterate through each (ShapeMask, ColorIndex) pair
354 for (const auto &[mask, index] : shape_tile.colors()) {
355 // Look up the actual color from the ColorIndexMap
356 auto color_opt = color_index_map.color_at_index(index);
357 if (!color_opt) {
358 panic("ColorIndex not found in ColorIndexMap");
359 }
360
361 const PixelType &color = *color_opt;
362
363 // Set the mask with the pixel color in the result
364 result.set(mask, color);
365 }
366
367 return result;
368}
369
385template <SupportsTransparency ColorType, std::size_t N = 0>
386[[nodiscard]] PixelTile<ColorType>
388 requires requires(const ColorType &c) { c.is_transparent(); }
389{
390 return details::color_tile_from_index_tile_impl(index_tile, palette, ColorType{});
391}
392
409template <SupportsTransparency ColorType, std::size_t N = 0>
411 const PixelTile<IndexPixel> &index_tile, const Palette<ColorType, N> &palette, const ColorType &extrinsic)
412 requires requires(const ColorType &c) { c.is_transparent(c); }
413{
414 return details::color_tile_from_index_tile_impl(index_tile, palette, extrinsic);
415}
416
431template <SupportsTransparency ColorType, std::size_t N = 0>
432[[nodiscard]] PixelTile<IndexPixel>
434 requires requires(const ColorType &c) { c.is_transparent(c); }
435{
437 tile, palette, [](const ColorType &c) { return c.is_transparent(); });
438}
439
455template <SupportsTransparency ColorType, std::size_t N = 0>
457 const PixelTile<ColorType> &tile, const Palette<ColorType, N> &palette, const ColorType &extrinsic)
458 requires requires(const ColorType &c) { c.is_transparent(c); }
459{
461 tile, palette, [&extrinsic](const ColorType &c) { return c.is_transparent(extrinsic); });
462}
463
478template <SupportsTransparency ColorType, std::size_t N = 0>
480 const PixelTile<IndexPixel> &index_tile, const Palette<ColorType, N> &palette, const ColorType &extrinsic)
481 requires requires(const ColorType &c) { c.is_transparent(c); }
482{
483 const CanonicalPixelTile<ColorType> canonical{color_tile_from_index_tile(index_tile, palette, extrinsic)};
484 return static_cast<const PixelTile<ColorType> &>(canonical);
485}
486
487} // namespace porytiles
A bidirectional mapping between pixel color values and sequential integer indices.
std::optional< ColorIndex > index_at_color(const PixelType &color) const
Retrieves the index associated with a given color.
std::optional< PixelType > color_at_index(ColorIndex index) const
Retrieves the color associated with a given index.
Represents a color index value for palette operations.
Represents an indexed color pixel.
Represents a palette index value within a particular palette.
A generic palette container for colors that support transparency checking.
Definition palette.hpp:45
std::map< PaletteIndex, ColorType > index_to_color_map() const
Creates a map from palette indices to their colors.
Definition palette.hpp:310
std::size_t size() const
Returns the number of slots in the palette.
Definition palette.hpp:203
std::map< ColorType, PaletteIndex > color_to_index_map() const
Creates a map from colors to their palette indices.
Definition palette.hpp:291
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
bool is_transparent() const
Checks if this entire PixelTile is transparent (intrinsic transparency only).
PixelType at(std::size_t i) const
void set(std::size_t i, const PixelType &p)
Represents which pixels in an 8x8 tile are non-transparent.
void set(std::size_t row, std::size_t col)
Sets the bit at the specified row and column to 1.
An 8x8 tile backed by mask-based storage that maps shape regions to pixel values.
void set(const ShapeMask &mask, const PixelType &color)
Sets or updates the pixel value for a specific shape mask.
bool is_transparent() const
Checks if this entire ShapeTile is transparent.
const std::map< ShapeMask, PixelType > & colors() const
Returns the internal map of shape masks to pixel values.
PixelTile< IndexPixel > index_tile_from_color_tile_impl(const PixelTile< ColorType > &tile, const Palette< ColorType, N > &palette, TransparencyPredicate is_transparent_pred)
Helper function implementing the core color-to-index tile conversion logic.
ShapeTile< ColorIndex > from_pixel_tile_impl(const PixelTile< PixelType > &pixel_tile, const ColorIndexMap< PixelType > &color_index_map, TransparencyPredicate is_transparent_pred)
Helper function implementing the core PixelTile to ShapeTile conversion logic.
PixelTile< ColorType > color_tile_from_index_tile_impl(const PixelTile< IndexPixel > &index_tile, const Palette< ColorType, N > &palette, const ColorType &transparent_color)
Helper function implementing the core index-to-color tile conversion logic.
constexpr std::size_t side_length_pix
constexpr std::size_t size_pix
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.cpp:43
PixelTile< PixelType > from_shape_tile(const ShapeTile< ColorIndex > &shape_tile, const ColorIndexMap< PixelType > &color_index_map)
Converts a ShapeTile<ColorIndex> to a PixelTile using a ColorIndexMap.
@ canonical
Export tiles in canonical form without applying flip transformations.
PixelTile< IndexPixel > index_tile_from_color_tile(const PixelTile< ColorType > &tile, const Palette< ColorType, N > &palette)
Converts a PixelTile<ColorType> to indexed form using a palette (intrinsic transparency only).
PixelTile< ColorType > canonical_color_tile_from_index_tile(const PixelTile< IndexPixel > &index_tile, const Palette< ColorType, N > &palette, const ColorType &extrinsic)
Converts a PixelTile<IndexPixel> to its canonical color form using a palette (extrinsic transparency)...
ShapeTile< ColorIndex > from_pixel_tile(const PixelTile< PixelType > &pixel_tile, const ColorIndexMap< PixelType > &color_index_map)
Converts a PixelTile to a ShapeTile<ColorIndex> using a ColorIndexMap (intrinsic transparency).
ShapeTile< PixelType > shape_tile_to_pixel_colors(const ShapeTile< ColorIndex > &shape_tile, const ColorIndexMap< PixelType > &color_index_map)
Converts a ShapeTile<ColorIndex> to a ShapeTile<PixelType> using a ColorIndexMap.
PixelTile< ColorType > color_tile_from_index_tile(const PixelTile< IndexPixel > &index_tile, const Palette< ColorType, N > &palette)
Converts a PixelTile<IndexPixel> to a PixelTile<ColorType> using a palette (intrinsic transparency).