Porytiles
Loading...
Searching...
No Matches
shape_group_analyzer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstddef>
4#include <map>
5#include <vector>
6
13
14namespace porytiles {
15
32template <SupportsTransparency PixelType, typename TransparencyPredicate>
33[[nodiscard]] ShapeTile<PixelType>
34shape_tile_from_pixel_tile(const PixelTile<PixelType> &pixel_tile, TransparencyPredicate is_transparent_pred)
35{
36 std::map<PixelType, ShapeMask> color_to_mask;
37
38 for (std::size_t row = 0; row < tile::side_length_pix; ++row) {
39 for (std::size_t col = 0; col < tile::side_length_pix; ++col) {
40 const auto pixel = pixel_tile.at(row, col);
41 if (is_transparent_pred(pixel)) {
42 continue;
43 }
44 color_to_mask[pixel].set(row, col);
45 }
46 }
47
49 for (const auto &[color, mask] : color_to_mask) {
50 result.set(mask, color);
51 }
52 return result;
53}
54
83template <SupportsTransparency PixelType>
84[[nodiscard]] std::vector<ShapeGroup<PixelType>>
85analyze_shape_groups(const std::vector<PixelTile<PixelType>> &tiles, const PixelType &extrinsic)
86 requires requires(const PixelType &c) { c.is_transparent(c); }
87{
88 /*
89 * Use a comparator that compares ShapeTiles by shape only (ignoring pixel values). This groups tiles with
90 * the same geometric structure regardless of their color assignments.
91 */
92 auto shape_only_less = [](const ShapeTile<PixelType> &a, const ShapeTile<PixelType> &b) {
94 };
95
96 // Map canonical shape (by geometry only) -> list of members
97 std::map<ShapeTile<PixelType>, std::vector<ShapeGroupMember<PixelType>>, decltype(shape_only_less)> groups(
98 shape_only_less);
99
100 for (std::size_t i = 0; i < tiles.size(); ++i) {
101 auto shape_tile = shape_tile_from_pixel_tile(
102 tiles[i], [&extrinsic](const PixelType &c) { return c.is_transparent(extrinsic); });
103
104 // Skip fully transparent tiles
105 if (shape_tile.is_transparent()) {
106 continue;
107 }
108
109 CanonicalShapeTile<PixelType> canonical{shape_tile};
110
111 ShapeGroupMember<PixelType> member;
112 member.tile_index = i;
113 member.colors = canonical.colors();
114 member.h_flip = canonical.h_flip();
115 member.v_flip = canonical.v_flip();
116
117 // Use the canonical form (as ShapeTile) as the grouping key
118 groups[static_cast<const ShapeTile<PixelType> &>(canonical)].push_back(std::move(member));
119 }
120
121 // Filter to groups with 2+ members that have distinct color assignments
122 std::vector<ShapeGroup<PixelType>> result;
123 for (auto &[canonical_shape, members] : groups) {
124 if (members.size() < 2) {
125 continue;
126 }
127
128 // Check if there are at least 2 distinct color assignments
129 bool has_distinct_colors = false;
130 for (std::size_t j = 1; j < members.size(); ++j) {
131 if (members[j].colors != members[0].colors) {
132 has_distinct_colors = true;
133 break;
134 }
135 }
136
137 if (!has_distinct_colors) {
138 continue;
139 }
140
141 ShapeGroup<PixelType> group;
142 group.canonical_shape = canonical_shape;
143 group.members = std::move(members);
144 result.push_back(std::move(group));
145 }
146
147 return result;
148}
149
150} // namespace porytiles
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
PixelType at(std::size_t i) const
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.
static bool compare_shape_only(const ShapeTile &lhs, const ShapeTile &rhs)
Compares two ShapeTiles based ONLY on shape masks, ignoring pixel values.
bool is_transparent() const
Checks if this entire ShapeTile is transparent.
constexpr std::size_t side_length_pix
std::vector< ShapeGroup< PixelType > > analyze_shape_groups(const std::vector< PixelTile< PixelType > > &tiles, const PixelType &extrinsic)
Analyzes a collection of pixel tiles and groups them by canonical shape for tile sharing analysis.
@ canonical
Export tiles in canonical form without applying flip transformations.
ShapeTile< PixelType > shape_tile_from_pixel_tile(const PixelTile< PixelType > &pixel_tile, TransparencyPredicate is_transparent_pred)
Converts a PixelTile to a ShapeTile by grouping pixels by color into ShapeMasks.