16template <
typename PixelType>
39template <
typename PixelType>
57 panic(
"unhandled Layer value");
86 panic(
"unhandled LayerType value in dropped_layer_for");
100 return "northwest(" + std::to_string(
static_cast<std::uint8_t
>(layer)) +
")";
102 return "northeast(" + std::to_string(
static_cast<std::uint8_t
>(layer)) +
")";
104 return "southwest(" + std::to_string(
static_cast<std::uint8_t
>(layer)) +
")";
106 return "southeast(" + std::to_string(
static_cast<std::uint8_t
>(layer)) +
")";
108 panic(
"unhandled Subtile value");
132[[nodiscard]]
inline std::tuple<std::size_t, Layer, Subtile>
from_tile_index(std::size_t tile_index)
139 return {metatile_index, layer, subtile};
160 panic(
"tile_index (" + std::to_string(tile_index) +
") >= tiles_per_metatile");
167 return {layer, subtile};
175 std::size_t subtile_row,
176 std::size_t subtile_col)
179 "{} {}({})|{}|{}|{},{}",
189[[nodiscard]]
inline std::string
223template <SupportsTransparency PixelType>
238 requires requires(const PixelType &p) { p.is_transparent(); }
240 const bool bottom_transparent =
241 std::ranges::all_of(
bottom(), [](
const auto &tile) {
return tile.is_transparent(); });
242 const bool middle_transparent =
243 std::ranges::all_of(
middle(), [](
const auto &tile) {
return tile.is_transparent(); });
244 const bool top_transparent = std::ranges::all_of(
top(), [](
const auto &tile) {
return tile.is_transparent(); });
245 return bottom_transparent && middle_transparent && top_transparent;
258 requires requires(
const PixelType &p) { p.is_transparent(p); }
260 const bool bottom_transparent =
261 std::ranges::all_of(
bottom(), [=](
const auto &tile) {
return tile.is_transparent(extrinsic); });
262 const bool middle_transparent =
263 std::ranges::all_of(
middle(), [=](
const auto &tile) {
return tile.is_transparent(extrinsic); });
264 const bool top_transparent =
265 std::ranges::all_of(
top(), [=](
const auto &tile) {
return tile.is_transparent(extrinsic); });
266 return bottom_transparent && middle_transparent && top_transparent;
279 auto out_it = tiles.begin();
280 out_it = std::ranges::copy(
bottom(), out_it).out;
281 out_it = std::ranges::copy(
middle(), out_it).out;
282 std::ranges::copy(
top(), out_it);
295 requires requires(const PixelType &p) { p.is_transparent(); }
297 return infer_layer_mode_impl([](
const PixelType &pixel) {
return pixel.is_transparent(); });
309 requires requires(
const PixelType &p) { p.is_transparent(p); }
311 return infer_layer_mode_impl([&extrinsic](
const PixelType &pixel) {
return pixel.is_transparent(extrinsic); });
327 requires requires(const PixelType &p) { p.is_transparent(); }
329 return infer_layer_type_impl([](
const PixelType &pixel) {
return pixel.is_transparent(); });
346 requires requires(
const PixelType &p) { p.is_transparent(p); }
348 return infer_layer_type_impl([&extrinsic](
const PixelType &pixel) {
return pixel.is_transparent(extrinsic); });
361 panic(std::format(
"index {} out of bounds: must be [0,3]", i));
387 panic(std::format(
"index {} out of bounds: must be [0,3]", i));
389 bottom_[i] = std::move(tile);
402 panic(std::format(
"index {} out of bounds: must be [0,3]", i));
428 panic(std::format(
"index {} out of bounds: must be [0,3]", i));
430 middle_[i] = std::move(tile);
443 panic(std::format(
"index {} out of bounds: must be [0,3]", i));
469 panic(std::format(
"index {} out of bounds: must be [0,3]", i));
471 top_[i] = std::move(tile);
484 template <
typename TransparencyPredicate>
485 [[nodiscard]]
bool layer_has_content(
487 TransparencyPredicate is_transparent_pred)
const
489 return std::ranges::any_of(layer, [&is_transparent_pred](
const auto &tile) {
490 return std::ranges::any_of(
491 tile.pix(), [&is_transparent_pred](
const auto &pixel) { return !is_transparent_pred(pixel); });
503 template <
typename TransparencyPredicate>
504 [[nodiscard]]
LayerMode infer_layer_mode_impl(TransparencyPredicate is_transparent_pred)
const
506 const bool bottom_has_content = layer_has_content(bottom_, is_transparent_pred);
507 const bool middle_has_content = layer_has_content(middle_, is_transparent_pred);
508 const bool top_has_content = layer_has_content(top_, is_transparent_pred);
510 if (bottom_has_content && middle_has_content && top_has_content) {
524 template <
typename TransparencyPredicate>
525 [[nodiscard]]
LayerType infer_layer_type_impl(TransparencyPredicate is_transparent_pred)
const
528 const LayerMode mode = infer_layer_mode_impl(is_transparent_pred);
534 const bool bottom_has_content = layer_has_content(bottom_, is_transparent_pred);
535 const bool middle_has_content = layer_has_content(middle_, is_transparent_pred);
536 const bool top_has_content = layer_has_content(top_, is_transparent_pred);
539 if (bottom_has_content && !middle_has_content && top_has_content) {
543 if (bottom_has_content && (middle_has_content || !top_has_content)) {
565[[nodiscard]] std::vector<PixelTile<T>> decompose(
const std::vector<Metatile<T>> &metatiles)
567 std::vector<PixelTile<T>> tiles;
569 for (
const auto &mt : metatiles) {
570 tiles.append_range(mt.decompose());
A template for two-dimensional images with arbitrarily typed pixel values.
std::size_t width() const
std::size_t height() const
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
Abstract base class for applying text styling with context-aware formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > ¶ms) const
Formats a string with styled parameters using fmtlib syntax.
constexpr std::size_t side_length_pix
LayerMode
Specifies whether a metatile uses dual-layer or triple-layer mode.
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
std::string int_to_hex_str(T t)
Converts an integer value to a hexadecimal string with "0x" prefix.
LayerType
Specifies which layers of a metatile are used for rendering.
Utility functions for string manipulation and formatting.