54 constexpr int kWidth = 512;
55 constexpr int kHeight = 512;
56 constexpr int kPixelCount = kWidth * kHeight;
59 static int last_room_id = -1;
60 if (room.
id() != last_room_id) {
61 last_room_id = room.
id();
63 "Room %03X: BG1_Layout(vis=%d,blend=%d) "
64 "BG1_Objects(vis=%d,blend=%d) BG2_Layout(vis=%d,blend=%d) "
65 "BG2_Objects(vis=%d,blend=%d) MergeType=%d",
89 const auto& bitmap = buffer.bitmap();
90 return bitmap.is_active() && bitmap.width() > 0;
98 const bool game_color_math =
100 const bool bg2_layout_translucent =
103 const bool bg2_objects_translucent =
109 (bg2_layout_translucent || bg2_objects_translucent);
110 const int depth = true_color ? 32 : 8;
111 if (output.
width() != kWidth || output.
height() != kHeight ||
112 output.
depth() != depth) {
113 output.
Create(kWidth, kHeight, depth,
114 std::vector<uint8_t>(kPixelCount * (true_color ? 4 : 1), 0));
120 bool palette_copied =
false;
121 std::array<SDL_Color, 256> pal_lut{};
122 pal_lut.fill({0, 0, 0, 255});
127 if (game_color_math) {
131 if (index < 0 || index >=
static_cast<int>(mask.size())) {
134 const uint8_t value = mask[index];
135 const bool layout_reveal =
139 const bool object_reveal =
143 return layout_reveal || object_reveal;
147 auto CopyPaletteIfNeeded = [&](
const gfx::Bitmap& src_bitmap) {
148 if (!palette_copied && src_bitmap.surface()) {
149 if (
const auto* palette = src_bitmap.surface()->format->palette) {
150 std::copy_n(palette->colors, std::min(palette->ncolors, 256),
153 pal_lut[0] = {0, 0, 0, 255};
154 pal_lut[255] = {0, 0, 0, 0};
156 ApplySDLPaletteToBitmap(src_bitmap.surface(), output);
157 palette_copied =
true;
171 CopyPaletteIfNeeded(bg1_layout.bitmap());
174 CopyPaletteIfNeeded(bg1_objects.bitmap());
177 CopyPaletteIfNeeded(bg2_layout.bitmap());
180 CopyPaletteIfNeeded(bg2_objects.bitmap());
183 const auto& upper_layout_px = bg1_layout.bitmap().data();
184 const auto& upper_object_px = bg1_objects.bitmap().data();
185 const auto& lower_layout_px = bg2_layout.bitmap().data();
186 const auto& lower_object_px = bg2_objects.bitmap().data();
187 const auto& upper_object_coverage = bg1_objects.coverage_data();
188 const auto& lower_object_coverage = bg2_objects.coverage_data();
190 auto resolve_tilemap_pixel =
191 [&](
bool layout_on,
bool objects_on,
const uint8_t* layout_pixels,
192 const uint8_t* object_pixels,
193 const std::vector<uint8_t>& object_coverage,
int index) -> uint8_t {
195 const bool object_wrote =
196 (index < static_cast<int>(object_coverage.size()) &&
197 object_coverage[index] != 0) ||
200 return object_pixels[index];
203 return layout_on ? layout_pixels[index] : 255;
207 for (
int idx = 0; idx < kPixelCount; ++idx) {
208 const uint8_t upper_pixel =
209 resolve_tilemap_pixel(bg1_layout_on, bg1_obj_on, upper_layout_px,
210 upper_object_px, upper_object_coverage, idx);
211 const uint8_t lower_pixel =
212 resolve_tilemap_pixel(bg2_layout_on, bg2_obj_on, lower_layout_px,
213 lower_object_px, lower_object_coverage, idx);
216 dst_data[idx] = upper_pixel;
218 dst_data[idx] = lower_pixel;
238 CopyPaletteIfNeeded(bg1_layout.bitmap());
241 CopyPaletteIfNeeded(bg1_objects.bitmap());
244 CopyPaletteIfNeeded(bg2_layout.bitmap());
247 CopyPaletteIfNeeded(bg2_objects.bitmap());
250 auto write_color = [&](
int pixel, SDL_Color color) {
257 auto write_index = [&](
int pixel, uint8_t index) {
259 write_color(pixel, pal_lut[index]);
264 auto blend_color = [&](uint8_t main_index, uint8_t sub_index) {
265 const auto&
main = pal_lut[main_index];
266 const auto& sub = pal_lut[sub_index];
267 const auto channel = [&](uint8_t m, uint8_t s) {
271 return SDL_Color{channel(
main.r, sub.r), channel(
main.g, sub.g),
272 channel(
main.b, sub.b), 255};
275 auto normalize_pri = [](uint8_t pri) -> uint8_t {
277 return (pri == 0xFF) ? 0 : (pri ? 1 : 0);
284 auto rank_for = [&](
bool is_bg1, uint8_t pri) ->
int {
286 const bool first = lower_wins_ties ? !is_bg1 : is_bg1;
293 const auto& bg1_layout_px = bg1_layout.bitmap().data();
294 const auto& bg1_obj_px = bg1_objects.bitmap().data();
295 const auto& bg2_layout_px = bg2_layout.bitmap().data();
296 const auto& bg2_obj_px = bg2_objects.bitmap().data();
297 const auto& bg1_layout_pri = bg1_layout.priority_data();
298 const auto& bg1_obj_pri = bg1_objects.priority_data();
299 const auto& bg2_layout_pri = bg2_layout.priority_data();
300 const auto& bg2_obj_pri = bg2_objects.priority_data();
301 const auto& bg1_obj_cov = bg1_objects.coverage_data();
302 const auto& bg2_obj_cov = bg2_objects.coverage_data();
304 for (
int idx = 0; idx < kPixelCount; ++idx) {
306 uint8_t bg1_pixel = 255;
308 const bool bg1_obj_wrote =
309 bg1_obj_on && ((idx < static_cast<int>(bg1_obj_cov.size()) &&
310 bg1_obj_cov[idx] != 0) ||
313 if (!bg1_revealed_at(bg1_objects, idx)) {
314 bg1_pixel = bg1_obj_px[idx];
315 bg1_pri = bg1_obj_pri[idx];
317 }
else if (bg1_layout_on && !
IsTransparent(bg1_layout_px[idx])) {
318 if (!bg1_revealed_at(bg1_layout, idx)) {
319 bg1_pixel = bg1_layout_px[idx];
320 bg1_pri = bg1_layout_pri[idx];
324 uint8_t bg2_pixel = 255;
326 bool bg2_pixel_translucent =
false;
327 const bool bg2_obj_wrote =
328 bg2_obj_on && ((idx < static_cast<int>(bg2_obj_cov.size()) &&
329 bg2_obj_cov[idx] != 0) ||
332 bg2_pixel = bg2_obj_px[idx];
333 bg2_pri = bg2_obj_pri[idx];
334 bg2_pixel_translucent = bg2_objects_translucent;
335 }
else if (bg2_layout_on && !
IsTransparent(bg2_layout_px[idx])) {
336 bg2_pixel = bg2_layout_px[idx];
337 bg2_pri = bg2_layout_pri[idx];
338 bg2_pixel_translucent = bg2_layout_translucent;
343 if (game_color_math && (
cgadsub_ & 0x20) && bg2_pixel_translucent &&
344 (bg1_layout_on || bg1_obj_on)) {
348 write_color(idx, blend_color(0, bg2_pixel));
350 write_index(idx, bg2_pixel);
356 write_index(idx, bg1_pixel);
361 const int r1 = rank_for(
true, bg1_pri);
362 const int r2 = rank_for(
false, bg2_pri);
367 if (bg2_pixel_translucent && true_color) {
368 write_color(idx, blend_color(bg1_pixel, bg2_pixel));
370 write_index(idx, (r1 >= r2) ? bg1_pixel : bg2_pixel);
387 if (!layer_enabled(layer_type, buffer))
390 const auto& src_bitmap = buffer.
bitmap();
393 CopyPaletteIfNeeded(src_bitmap);
395 const auto& src_data = src_bitmap.data();
401 for (
int idx = 0; idx < kPixelCount; ++idx) {
404 if (is_bg1_layer && bg1_revealed_at(buffer, idx)) {
407 uint8_t src_pixel = src_data[idx];
414 switch (blend_mode) {
417 dst_data[idx] = src_pixel;
424 dst_data[idx] = src_pixel;
433 dst_data[idx] = src_pixel;
435 dst_data[idx] = src_pixel;
441 dst_data[idx] = src_pixel;
460 if (!palette_copied && !true_color) {
461 const auto& bg1_bitmap = room.
bg1_buffer().bitmap();
462 if (bg1_bitmap.surface()) {
463 ApplySDLPaletteToBitmap(bg1_bitmap.surface(), output);
474 SDL_SetColorKey(output.
surface(), true_color ? SDL_FALSE : SDL_TRUE, 255);
475 SDL_SetSurfaceBlendMode(output.
surface(), SDL_BLENDMODE_BLEND);
481 SDL_SetSurfaceColorMod(output.
surface(), 128, 128, 128);
484 SDL_SetSurfaceColorMod(output.
surface(), 255, 255, 255);