Porytiles
Loading...
Searching...
No Matches
layer_mode_converter.cpp
Go to the documentation of this file.
2
11
12namespace porytiles {
13
15{
17 layer_mode, component.detect_layer_mode(), std::vector<TilemapEntry>, "Layer mode detection failed.");
18 if (layer_mode == LayerMode::triple) {
19 // No-op case
20 return component.metatiles_bin();
21 }
22
23 const auto &metatiles_bin = component.metatiles_bin();
24 const auto &metatile_attributes = component.metatile_attributes_bin();
25
26 const std::size_t num_metatiles = metatiles_bin.size() / metatile::entries_per_metatile_dual;
27
28 std::vector<TilemapEntry> result;
29 result.reserve(num_metatiles * metatile::entries_per_metatile_triple);
30
31 // Create a transparent entry (tile_index = 0, palette_index = 0, no flips)
32 const TilemapEntry transparent{0, 0, false, false};
33
34 for (std::size_t i = 0; i < num_metatiles; ++i) {
35 // Number of transparent entries to insert
36 constexpr std::size_t transparent_entries = 4;
37 const auto &attribute = metatile_attributes[i];
38 const std::size_t input_offset = i * metatile::entries_per_metatile_dual;
39
40 switch (attribute.layer_type()) {
42 // Insert 4 transparent entries at the start
43 for (std::size_t j = 0; j < transparent_entries; ++j) {
44 result.push_back(transparent);
45 }
46 // Copy the 8 original entries
47 for (std::size_t j = 0; j < metatile::entries_per_metatile_dual; ++j) {
48 result.push_back(metatiles_bin[input_offset + j]);
49 }
50 break;
51
53 // Copy the 8 original entries
54 for (std::size_t j = 0; j < metatile::entries_per_metatile_dual; ++j) {
55 result.push_back(metatiles_bin[input_offset + j]);
56 }
57 // Insert 4 transparent entries at the end
58 for (std::size_t j = 0; j < transparent_entries; ++j) {
59 result.push_back(transparent);
60 }
61 break;
62
64 // Copy the first 4 entries
65 for (std::size_t j = 0; j < transparent_entries; ++j) {
66 result.push_back(metatiles_bin[input_offset + j]);
67 }
68 // Insert 4 transparent entries in the middle
69 for (std::size_t j = 0; j < transparent_entries; ++j) {
70 result.push_back(transparent);
71 }
72 // Copy the last 4 entries
73 for (std::size_t j = transparent_entries; j < metatile::entries_per_metatile_dual; ++j) {
74 result.push_back(metatiles_bin[input_offset + j]);
75 }
76 break;
77 }
78 }
79
80 return result;
81}
82
83[[nodiscard]] std::vector<TilemapEntry> LayerModeConverter::dual_layerize(
84 const std::vector<TilemapEntry> &entries,
85 const std::vector<Metatile<Rgba32>> &source_metatiles,
86 const std::vector<std::optional<LayerType>> &explicit_layer_types)
87{
88 const std::size_t expected_entries_size = source_metatiles.size() * metatile::entries_per_metatile_triple;
89 if (entries.size() != expected_entries_size) {
90 panic(
91 "entries vector size " + std::to_string(entries.size()) + " did not match expected size " +
92 std::to_string(expected_entries_size));
93 }
94
95 std::vector<TilemapEntry> result;
96 result.reserve(source_metatiles.size() * metatile::entries_per_metatile_dual);
97
98 for (std::size_t i = 0; i < source_metatiles.size(); ++i) {
99 const auto &metatile = source_metatiles[i];
100 const std::size_t input_offset = i * metatile::entries_per_metatile_triple;
101
102 // Implied-triple metatiles are legal input here: validate_layer_mode is the gate, and with
103 // ignore_triple_layer_content on it lets them through to be reduced by dropping a layer group. infer_layer_type
104 // has no meaningful answer for an implied-triple metatile, so it falls back to 'normal' (which drops the bottom
105 // group). An explicit pin still wins over that fallback, so the drop logic below is unchanged; the only
106 // difference is the enriched warning when such a metatile drops visible content.
107 const LayerMode layer_mode = metatile.infer_layer_mode(extrinsic_transparency_);
108 const bool is_implied_triple = layer_mode == LayerMode::triple;
109
110 // An explicit override wins over inference and drives which layer group is dropped.
111 const LayerType inferred = metatile.infer_layer_type(extrinsic_transparency_);
112 const LayerType layer_type = (i < explicit_layer_types.size() && explicit_layer_types[i].has_value())
113 ? explicit_layer_types[i].value()
114 : inferred;
115
116 // The layer group this type drops. Warn if any dropped entry references a visible (non-transparent) tile, which
117 // means the reduction would silently discard real tiles. Inspect the actual entries here (post anim overrides),
118 // not the source RGBA transparency, so overrides that made an entry visible are caught.
119 const std::size_t drop_begin = layer_type == LayerType::normal ? 0 : (layer_type == LayerType::covered ? 8 : 4);
120 bool drops_visible = false;
121 for (std::size_t j = drop_begin; j < drop_begin + 4; ++j) {
122 if (entries[input_offset + j].tile_index() != 0) {
123 drops_visible = true;
124 break;
125 }
126 }
127 if (drops_visible) {
128 std::vector<std::string> lines;
129 lines.push_back(diag_->formatter().format(
130 "Metatile {}: layer type '{}' drops a layer that contains visible tiles. Those tiles will be "
131 "discarded.",
132 FormatParam{i},
134 if (is_implied_triple) {
135 lines.push_back(diag_->formatter().format(
136 "This metatile has content on all three layers. Pin its layer type via a '{}' layer_type pin to "
137 "control which layer is dropped.",
138 FormatParam{"fieldmap.role_pins", Style::bold}));
139 }
140 diag_->warning("dual-layer-drop", lines);
141 }
142
143 switch (layer_type) {
145 // Skip first 4 transparent entries, copy next 8
146 for (std::size_t j = 4; j < metatile::entries_per_metatile_triple; ++j) {
147 result.push_back(entries[input_offset + j]);
148 }
149 break;
150
152 // Copy first 8 entries, skip last 4 transparent
153 for (std::size_t j = 0; j < metatile::entries_per_metatile_dual; ++j) {
154 result.push_back(entries[input_offset + j]);
155 }
156 break;
157
158 case LayerType::split:
159 // Copy first 4, skip middle 4 transparent, copy last 4
160 for (std::size_t j = 0; j < 4; ++j) {
161 result.push_back(entries[input_offset + j]);
162 }
163 for (std::size_t j = 8; j < metatile::entries_per_metatile_triple; ++j) {
164 result.push_back(entries[input_offset + j]);
165 }
166 break;
167 }
168 }
169
170 return result;
171}
172
173} // namespace porytiles
#define PT_TRY_ASSIGN_CHAIN_ERR(var, expr, return_type,...)
Unwraps a ChainableResult, chaining a new error message on failure.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
A text parameter with associated styling for formatted output.
ChainableResult< std::vector< TilemapEntry > > triple_layerize(const PorymapTilesetComponent &component)
Converts a tileset component to triple-layer format.
std::vector< TilemapEntry > dual_layerize(const std::vector< TilemapEntry > &entries, const std::vector< Metatile< Rgba32 > > &source_metatiles, const std::vector< std::optional< LayerType > > &explicit_layer_types={})
Converts a tileset from triple-layer format to dual-layer format.
The core tileset entity - a 2x2 grid of PixelTile objects arranged into three layers.
Definition metatile.hpp:224
const std::vector< TilemapEntry > & metatiles_bin() const
ChainableResult< LayerMode > detect_layer_mode() const
const std::vector< MetatileAttribute > & metatile_attributes_bin() const
static const Style bold
Bold text formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > &params) const
Formats a string with styled parameters using fmtlib syntax.
Represents a tilemap entry referencing a tile with palette and flip attributes.
const TextFormatter & formatter() const
virtual void warning(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged warning message.
constexpr std::size_t entries_per_metatile_dual
Definition metatile.hpp:25
constexpr std::size_t entries_per_metatile_triple
Definition metatile.hpp:26
LayerMode
Specifies whether a metatile uses dual-layer or triple-layer mode.
Definition layer.hpp:20
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.cpp:43
std::string layer_type_csv_token(LayerType layer_type)
Converts a LayerType to its lowercase CSV token.
Definition layer.hpp:128
LayerType
Specifies which layers of a metatile are used for rendering.
Definition layer.hpp:86