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
30template <SupportsTransparency PixelType, typename TransparencyPredicate>
31[[nodiscard]] ShapeTile<PixelType>
32shape_tile_from_pixel_tile(const PixelTile<PixelType> &pixel_tile, TransparencyPredicate is_transparent_pred)
33{
34 std::map<PixelType, ShapeMask> color_to_mask;
35
36 for (std::size_t row = 0; row < tile::side_length_pix; ++row) {
37 for (std::size_t col = 0; col < tile::side_length_pix; ++col) {
38 const auto pixel = pixel_tile.at(row, col);
39 if (is_transparent_pred(pixel)) {
40 continue;
41 }
42 color_to_mask[pixel].set(row, col);
43 }
44 }
45
47 for (const auto &[color, mask] : color_to_mask) {
48 result.set(mask, color);
49 }
50 return result;
51}
52
79template <SupportsTransparency PixelType>
80[[nodiscard]] std::vector<ShapeGroup<PixelType>>
81analyze_shape_groups(const std::vector<PixelTile<PixelType>> &tiles, const PixelType &extrinsic)
82 requires requires(const PixelType &c) { c.is_transparent(c); }
83{
84 // Use a comparator that compares ShapeTiles by shape only (ignoring pixel values). This groups tiles with
85 // the same geometric structure regardless of their color assignments.
86 auto shape_only_less = [](const ShapeTile<PixelType> &a, const ShapeTile<PixelType> &b) {
88 };
89
90 // Map canonical shape (by geometry only) -> list of members
91 std::map<ShapeTile<PixelType>, std::vector<ShapeGroupMember<PixelType>>, decltype(shape_only_less)> groups(
92 shape_only_less);
93
94 for (std::size_t i = 0; i < tiles.size(); ++i) {
95 auto shape_tile = shape_tile_from_pixel_tile(
96 tiles[i], [&extrinsic](const PixelType &c) { return c.is_transparent(extrinsic); });
97
98 // Skip fully transparent tiles
99 if (shape_tile.is_transparent()) {
100 continue;
101 }
102
103 CanonicalShapeTile<PixelType> canonical{shape_tile};
104
105 ShapeGroupMember<PixelType> member;
106 member.tile_index = i;
107 member.colors = canonical.colors();
108 member.h_flip = canonical.h_flip();
109 member.v_flip = canonical.v_flip();
110
111 // Use the canonical form (as ShapeTile) as the grouping key
112 groups[static_cast<const ShapeTile<PixelType> &>(canonical)].push_back(std::move(member));
113 }
114
115 // Filter to groups with 2+ members that have distinct color assignments
116 std::vector<ShapeGroup<PixelType>> result;
117 for (auto &[canonical_shape, members] : groups) {
118 if (members.size() < 2) {
119 continue;
120 }
121
122 // Check if there are at least 2 distinct color assignments
123 bool has_distinct_colors = false;
124 for (std::size_t j = 1; j < members.size(); ++j) {
125 if (members[j].colors != members[0].colors) {
126 has_distinct_colors = true;
127 break;
128 }
129 }
130
131 if (!has_distinct_colors) {
132 continue;
133 }
134
135 ShapeGroup<PixelType> group;
136 group.canonical_shape = canonical_shape;
137 group.members = std::move(members);
138 result.push_back(std::move(group));
139 }
140
141 return result;
142}
143
144} // 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.