17namespace draw_routines {
21constexpr int kThievesTownEastAtticRoomId = 0x65;
25 return tiles[index % tiles.size()];
29 int h, std::span<const gfx::TileInfo> tiles,
30 size_t start_index = 0) {
34 size_t index = start_index;
35 for (
int x = 0; x < w; ++x) {
36 for (
int y = 0; y < h; ++y) {
44 int h, std::span<const gfx::TileInfo> tiles,
45 size_t start_index = 0) {
49 size_t index = start_index;
50 for (
int y = 0; y < h; ++y) {
51 for (
int x = 0; x < w; ++x) {
61 columns, 3, ctx.
tiles, start_index);
66 ctx.
tiles, start_index);
71 ctx.
tiles, start_index);
81 if (ctx.
tiles.size() < 64)
91 std::span<const gfx::TileInfo> tiles) {
96 std::span<const gfx::TileInfo> tiles) {
108 if (ctx.
tiles.size() < 8)
125 constexpr size_t kSpanTiles = 40;
126 const bool use_open_tiles = ctx.
state !=
nullptr &&
128 ctx.
tiles.size() >= kSpanTiles * 2;
129 const size_t start_index = use_open_tiles ? kSpanTiles : 0;
130 if (ctx.
tiles.size() < start_index + kSpanTiles)
138 if (index >= ctx.
tiles.size())
146 size_t start_index,
int columns) {
147 for (
int x = 0; x < columns; ++x) {
148 for (
int y = 0; y < 3; ++y) {
155 size_t start_index) {
163 size_t start_index) {
174 0x3C15, 0x3C15, 0x3C15};
177 std::array<gfx::TileInfo, 3> fill_tiles;
178 for (
size_t i = 0; i < fill_tiles.size(); ++i) {
180 if (ctx.
rom !=
nullptr) {
182 static_cast<int>(i * 2));
195 for (
int x = 0; x < column_count; ++x) {
198 for (
int y = 1; y < height - 1; ++y) {
203 ctx.
object.
y_ + height - 1, fill_tiles[2]);
210 for (
int i = 0; i < direction; ++i) {
221 size_t start_index,
int fill_width) {
224 for (
int i = 0; i < fill_width; ++i) {
228 const int left_cap_x = 1 + fill_width;
231 for (
int i = 0; i < 4; ++i) {
235 const int right_cap_x = left_cap_x + 5;
238 for (
int i = 0; i < fill_width; ++i) {
251 if (!is_open && ctx.
state) {
258 size_t start_index = is_open && ctx.
tiles.size() >= 32 ? 16 : 0;
259 for (
int x = 0; x < 4; ++x) {
260 for (
int y = 0; y < 4; ++y) {
263 ctx.
tiles[start_index +
static_cast<size_t>(x * 4 + y)]);
269 size_t start_index = 0;
270 if (is_open && ctx.
object.
id_ == 0xF99 && ctx.
tiles.size() >= 8) {
273 if (ctx.
tiles.size() < start_index + 4) {
278 ctx.
tiles[start_index]);
280 ctx.
tiles[start_index + 1]);
282 ctx.
tiles[start_index + 2]);
301 if (ctx.
tiles.size() >= 1) {
313 if (!result.ok() || !result.value() || result.value()->IsEmpty()) {
315 if (ctx.
tiles.size() >= 1) {
322 const auto& custom_obj = *result.value();
324 for (
const auto& entry : custom_obj.tiles) {
327 uint8_t lo =
static_cast<uint8_t
>(entry.tile_data & 0xFF);
328 uint8_t hi =
static_cast<uint8_t
>((entry.tile_data >> 8) & 0xFF);
333 int draw_x = ctx.
object.
x_ + entry.rel_x;
334 int draw_y = ctx.
object.
y_ + entry.rel_y;
347 if (ctx.
tiles.size() >= 2) {
352 if (ctx.
tiles.size() >
static_cast<size_t>(tile_index)) {
354 ctx.
tiles[tile_index]);
362 if (ctx.
tiles.empty()) {
374 if (ctx.
tiles.size() >= 4) {
391 if (ctx.
tiles.size() >=
static_cast<size_t>(width * height)) {
392 for (
int y = 0; y < height; ++y) {
393 for (
int x = 0; x < width; ++x) {
396 ctx.
tiles[y * width + x]);
410 Draw1x3NRightwards(ctx, 6, 0);
415 Draw1x3NRightwards(ctx, 6, 0);
421 Draw1x3NRightwards(ctx, 8, 0);
427 if (ctx.
tiles.size() < 8)
436 if (ctx.
tiles.size() < 48)
451 if (ctx.
tiles.size() < 16)
465 if (ctx.
tiles.size() < 84)
468 constexpr std::array<int, 14> kSourceColumns = {
469 0, 1, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1, 0,
471 for (
int y = 0; y < 14; ++y) {
472 for (
int x = 0; x < 14; ++x) {
474 if (x >= 7 && x <= 12) {
476 }
else if (x == 13) {
488 if (ctx.
tiles.size() < 26)
491 auto write = [&](
int dx,
int dy,
size_t tile_index,
492 bool force_horizontal_mirror =
false,
493 bool toggle_horizontal_mirror =
false) {
495 if (force_horizontal_mirror) {
497 }
else if (toggle_horizontal_mirror) {
505 for (
int section = 0; section < 6; ++section) {
506 const int x = section * 2;
512 write(x + 2, 2, 1,
true);
517 for (
int row = 0; row < 3; ++row) {
518 const size_t wall_tile =
static_cast<size_t>(2 + row);
519 const size_t center_tile =
static_cast<size_t>(5 + row);
520 const int y = 3 + row;
522 for (
int x : {0, 2, 10, 12}) {
523 write(x, y, wall_tile);
525 for (
int x : {1, 3, 11, 13}) {
526 write(x, y, wall_tile,
true);
528 for (
int x : {4, 6, 8}) {
529 write(x, y, center_tile);
531 for (
int x : {5, 7, 9}) {
532 write(x, y, center_tile,
true);
539 write(13, 0, 8,
true);
540 write(13, 1, 8,
true);
542 write(13, 2, 9,
true);
546 for (
int row = 0; row < 4; ++row) {
547 const int y = 10 + row;
548 write(3, y,
static_cast<size_t>(10 + row));
549 write(10, y,
static_cast<size_t>(10 + row),
552 write(4, y,
static_cast<size_t>(14 + row));
553 write(9, y,
static_cast<size_t>(14 + row),
556 write(5, y,
static_cast<size_t>(18 + row));
557 write(8, y,
static_cast<size_t>(18 + row),
560 write(6, y,
static_cast<size_t>(22 + row));
561 write(7, y,
static_cast<size_t>(22 + row),
571 if (ctx.
tiles.size() < 56)
582 if (ctx.
tiles.empty())
586 for (
int x = 0; x < 3; ++x) {
589 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(x)));
593 for (
int y = 1; y <= 3; ++y) {
594 for (
int x = 0; x < 3; ++x) {
597 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(3 + x)));
602 for (
int x = 0; x < 3; ++x) {
605 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(6 + x)));
612 if (ctx.
tiles.empty())
614 Draw1x3NRightwards(ctx, 4, 0, 0);
615 Draw1x3NRightwards(ctx, 4, 12, 3);
628 if (ctx.
tiles.size() < 32)
630 Draw4x4ColumnMajor(ctx, 0, 0, 0);
631 Draw4x4ColumnMajor(ctx, 0, 2, 0);
632 Draw4x4ColumnMajor(ctx, 0, 6, 16);
641 if (ctx.
state !=
nullptr &&
645 DrawFloorLightGrid(ctx);
650 DrawFloorLightGrid(ctx);
655 Draw4x4ColumnMajor(ctx, 0, 0, 0);
663 if (ctx.
tiles.size() < 8)
666 for (
int block_y = 0; block_y < 2; ++block_y) {
667 for (
int block_x = 0; block_x < 5; ++block_x) {
682 if (ctx.
tiles.empty())
684 Draw1x3NRightwards(ctx, 3, 0, 0);
685 Draw1x3NRightwards(ctx, 3, 9, 3);
691 if (ctx.
tiles.empty())
694 Draw4x4ColumnMajor(ctx, 2, 0, 0);
695 Draw4x4ColumnMajor(ctx, 0, 4, 16);
696 Draw4x4ColumnMajor(ctx, 4, 4, 16);
702 if (ctx.
tiles.size() < 4)
717 if (ctx.
tiles.size() < 16)
721 for (
int x = 0; x < 4; ++x) {
722 for (
int y = 0; y < 4; ++y) {
731 if (ctx.
tiles.size() < 12)
735 for (
int x = 0; x < 4; ++x) {
736 for (
int y = 0; y < 3; ++y) {
748 ctx.
tiles.size() < 2) {
752 constexpr std::array<int, 3> kTopRows = {0, 3, 6};
753 constexpr std::array<int, 3> kBottomRows = {1, 4, 7};
754 for (
int col = 0; col < 3; ++col) {
755 const int x = ctx.
object.
x_ + col * 2;
756 for (
int row : kTopRows) {
760 for (
int row : kBottomRows) {
775 if (ctx.
tiles.empty())
779 const int middle_columns = (size + 1) * 2;
781 Draw1x5Column(ctx, 0, 0);
782 for (
int i = 0; i < middle_columns; ++i) {
783 Draw1x5Column(ctx, 1 + i, 5);
785 Draw1x5Column(ctx, 1 + middle_columns, 10);
791 if (ctx.
tiles.empty())
795 const int middle_columns = (size + 1) * 2;
799 for (
int i = 0; i < middle_columns; ++i) {
822 "Draw4x4BlocksIn4x4SuperSquare: obj=0x%03X pos=(%d,%d) size=0x%02X "
823 "tiles=%zu size_x=%d size_y=%d",
825 ctx.
tiles.size(), size_x, size_y);
827 if (ctx.
tiles.empty()) {
829 "Draw4x4BlocksIn4x4SuperSquare: SKIPPING - no tiles loaded!");
834 const auto& tile = ctx.
tiles[0];
836 "Draw4x4BlocksIn4x4SuperSquare: tile[0] id=%d palette=%d", tile.id_,
839 for (
int sy = 0; sy < size_y; ++sy) {
840 for (
int sx = 0; sx < size_x; ++sx) {
842 int base_x = ctx.
object.
x_ + (sx * 4);
843 int base_y = ctx.
object.
y_ + (sy * 4);
846 for (
int y = 0; y < 4; ++y) {
847 for (
int x = 0; x < 4; ++x) {
862 if (ctx.
tiles.empty())
865 const auto& tile = ctx.
tiles[0];
866 for (
int sy = 0; sy < size_y; ++sy) {
867 for (
int sx = 0; sx < size_x; ++sx) {
868 int base_x = ctx.
object.
x_ + (sx * 3);
869 int base_y = ctx.
object.
y_ + (sy * 3);
871 for (
int y = 0; y < 3; ++y) {
872 for (
int x = 0; x < 3; ++x) {
888 if (ctx.
tiles.empty())
890 if (ctx.
tiles.size() < 8) {
897 for (
int sy = 0; sy < size_y; ++sy) {
898 for (
int sx = 0; sx < size_x; ++sx) {
899 int base_x = ctx.
object.
x_ + (sx * 4);
900 int base_y = ctx.
object.
y_ + (sy * 4);
914 if (ctx.
tiles.size() < 8) {
919 for (
int sy = 0; sy < size_y; ++sy) {
920 for (
int sx = 0; sx < size_x; ++sx) {
921 int base_x = ctx.
object.
x_ + (sx * 4);
922 int base_y = ctx.
object.
y_ + (sy * 4);
935 if (ctx.
tiles.size() < 8) {
940 for (
int sy = 0; sy < size_y; ++sy) {
941 for (
int sx = 0; sx < size_x; ++sx) {
942 int base_x = ctx.
object.
x_ + (sx * 4);
943 int base_y = ctx.
object.
y_ + (sy * 4);
955 if (ctx.
tiles.size() < 24)
972 for (
int xx = 1; xx < max; ++xx) {
973 for (
int yy = 1; yy < max; ++yy) {
983 for (
int yy = 1; yy < max; ++yy) {
997 if (ctx.
tiles.size() < 4)
1000 for (
int sy = 0; sy < size_y; ++sy) {
1001 for (
int sx = 0; sx < size_x; ++sx) {
1002 int base_x = ctx.
object.
x_ + (sx * 2);
1003 int base_y = ctx.
object.
y_ + (sy * 2);
1021 if (ctx.
tiles.size() < 16)
1024 int right_x = ctx.
object.
x_ + (3 + (size_x * 2));
1025 int bottom_y = ctx.
object.
y_ + (3 + (size_y * 2));
1028 for (
int xx = 0; xx < size_x + 1; ++xx) {
1029 for (
int yy = 0; yy < size_y + 1; ++yy) {
1030 int base_x = ctx.
object.
x_ + (xx * 2);
1031 int base_y = ctx.
object.
y_ + (yy * 2);
1044 for (
int yy = 0; yy < size_y + 1; ++yy) {
1045 int base_y = ctx.
object.
y_ + (yy * 2);
1058 for (
int xx = 0; xx < size_x + 1; ++xx) {
1059 int base_x = ctx.
object.
x_ + (xx * 2);
1090 int count_x = size_x + 2;
1091 int count_y = size_y + 2;
1093 if (ctx.
tiles.empty())
1095 if (ctx.
tiles.size() < 8) {
1097 for (
int yy = 0; yy < count_y; ++yy) {
1098 for (
int xx = 0; xx < count_x; ++xx) {
1099 int base_x = ctx.
object.
x_ + (xx * 4);
1100 int base_y = ctx.
object.
y_ + (yy * 4);
1102 ctx.
tiles[
static_cast<size_t>((xx + yy) % ctx.
tiles.size())];
1103 for (
int y = 0; y < 4; ++y) {
1104 for (
int x = 0; x < 4; ++x) {
1114 for (
int yy = 0; yy < count_y; ++yy) {
1115 for (
int xx = 0; xx < count_x; ++xx) {
1116 int base_x = ctx.
object.
x_ + (xx * 4);
1117 int base_y = ctx.
object.
y_ + (yy * 4);
1119 for (
int x = 0; x < 4; ++x) {
1143 if (ctx.
tiles.size() < 16)
1168 if (ctx.
tiles.size() < 12)
1183 if (ctx.
tiles.size() < 16)
1198 if (ctx.
tiles.size() < 16)
1209 const bool south_lower =
1212 size_t tile_index = 0;
1213 for (
int col = 0; col < 4; ++col) {
1214 for (
int row = 0; row < 4; ++row) {
1215 const auto& tile = TileAtWrapped(ctx.
tiles, tile_index++);
1218 if ((!south_lower && row == 0) || (south_lower && row == 3)) {
1237 if (ctx.
tiles.size() < 6) {
1247 tile.horizontal_mirror_ =
true;
1251 for (
int col = 0; col < 5; ++col) {
1252 const int left_x = base_x + 2 + col;
1253 const int right_x = base_x + 9 + col;
1259 with_horizontal_mirror(ctx.
tiles[2]));
1263 with_horizontal_mirror(ctx.
tiles[4]));
1267 with_horizontal_mirror(ctx.
tiles[5]));
1272 with_horizontal_mirror(ctx.
tiles[0]));
1273 for (
int x_offset : {1, 7, 8, 14}) {
1280 with_horizontal_mirror(ctx.
tiles[3]));
1297 if (ctx.
tiles.size() < 16) {
1304 const bool is_open = ctx.
state !=
nullptr &&
1306 ctx.
tiles.size() >= 32;
1307 const size_t state_offset = is_open ? 16 : 0;
1309 for (
int block_y = 0; block_y < 2; ++block_y) {
1310 for (
int block_x = 0; block_x < 2; ++block_x) {
1311 const size_t block_offset =
1312 state_offset +
static_cast<size_t>((block_y * 2 + block_x) * 4);
1313 for (
int x = 0; x < 2; ++x) {
1314 for (
int y = 0; y < 2; ++y) {
1318 ctx.
tiles[block_offset +
static_cast<size_t>(x * 2 + y)]);
1328 ctx.
tiles.size() < 24) {
1334 const int height = direction * 2 + 6;
1338 DrawMovingWallFill(ctx, ctx.
object.
x_ - column_count, column_count, height);
1339 DrawMovingWallPlatform(ctx, direction);
1345 ctx.
tiles.size() < 24) {
1351 const int height = direction * 2 + 6;
1355 DrawMovingWallPlatform(ctx, direction);
1356 DrawMovingWallFill(ctx, ctx.
object.
x_ + 3, column_count, height);
1367 if (row_count <= 0 || tile_offset < 0 || ctx.
tiles.empty()) {
1371 if (tile_offset >=
static_cast<int>(ctx.
tiles.size())) {
1375 const int available_tiles =
static_cast<int>(ctx.
tiles.size()) - tile_offset;
1377 const int rows_to_draw = std::min(row_count, available_rows);
1379 for (
int row = 0; row < rows_to_draw; ++row) {
1384 ctx.
tiles[row_base + col]);
1399 const bool water_active =
1402 const int row_count = water_active ? 5 : 3;
1403 const int tile_offset = water_active ? 12 : 0;
1404 DrawWaterFaceRows(ctx, row_count, tile_offset);
1410 DrawWaterFaceRows(ctx, 5, 0);
1416 DrawWaterFaceRows(ctx, 7, 0);
1430 if (ctx.
tiles.size() < 68)
1433 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1435 const int width_blocks = size_x + 4;
1436 const int height_blocks = size_y + 1;
1439 DrawPlatform1x3Rightwards(ctx, 0, 0, 0,
1441 for (
int x = 0; x < width_blocks; ++x) {
1442 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, 0,
1445 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, 0,
1449 for (
int y = 0; y < height_blocks; ++y) {
1450 const int dy = 3 + y * 2;
1451 DrawPlatform3x2(ctx, 0, dy, 24);
1452 for (
int x = 0; x < width_blocks; ++x) {
1453 DrawPlatform2x2(ctx, 3 + x * 2, dy, 30);
1455 DrawPlatform3x2(ctx, 3 + width_blocks * 2, dy,
1460 const int bottom_y = 3 + height_blocks * 2;
1461 DrawPlatform1x3Rightwards(ctx, 0, bottom_y, 40,
1463 for (
int x = 0; x < width_blocks; ++x) {
1464 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, bottom_y,
1467 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, bottom_y,
1472 DrawPlatform2x2(ctx, width_blocks + 2,
1473 bottom_y - (height_blocks + 1),
1481 if (ctx.
tiles.size() < 21)
1484 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1486 const int fill_width = size_x + 1;
1487 const int body_rows = size_y * 2 + 5;
1489 for (
int row = 0; row < body_rows; ++row) {
1490 DrawOpenChestPlatformSegment(ctx, row, 0, fill_width);
1492 DrawOpenChestPlatformSegment(ctx, body_rows, 1, fill_width);
1493 DrawOpenChestPlatformSegment(ctx, body_rows + 1, 2,
1501 if (ctx.
tiles.size() < 3)
1504 for (
int x = 0; x < width; ++x) {
1505 size_t tile_idx = (x == 0) ? 0 : ((x == width - 1) ? 2 : 1);
1515 if (ctx.
tiles.empty())
1518 for (
int y = 0; y < height; ++y) {
1537 .draws_to_both_bgs =
false,
1548 .draws_to_both_bgs =
false,
1556 .name =
"DoorSwitcherer",
1558 .draws_to_both_bgs =
false,
1567 .name =
"SomariaLine",
1569 .draws_to_both_bgs =
false,
1578 .name =
"WaterFace",
1580 .draws_to_both_bgs =
false,
1593 .name =
"4x4BlocksIn4x4SuperSquare",
1595 .draws_to_both_bgs =
false,
1603 .name =
"3x3FloorIn4x4SuperSquare",
1605 .draws_to_both_bgs =
false,
1613 .name =
"4x4FloorIn4x4SuperSquare",
1615 .draws_to_both_bgs =
false,
1623 .name =
"4x4FloorOneIn4x4SuperSquare",
1625 .draws_to_both_bgs =
false,
1633 .name =
"4x4FloorTwoIn4x4SuperSquare",
1635 .draws_to_both_bgs =
false,
1643 .name =
"BigHole4x4_1to16",
1645 .draws_to_both_bgs =
false,
1653 .name =
"Spike2x2In4x4SuperSquare",
1655 .draws_to_both_bgs =
false,
1663 .name =
"TableRock4x4_1to16",
1665 .draws_to_both_bgs =
false,
1673 .name =
"WaterOverlay8x8_1to16",
1675 .draws_to_both_bgs =
false,
1684 .name =
"InterRoomFatStairsUp",
1686 .draws_to_both_bgs =
false,
1695 .name =
"InterRoomFatStairsDownA",
1697 .draws_to_both_bgs =
false,
1706 .name =
"InterRoomFatStairsDownB",
1708 .draws_to_both_bgs =
false,
1717 .name =
"AutoStairs",
1719 .draws_to_both_bgs =
false,
1728 .name =
"StraightInterRoomStairs",
1730 .draws_to_both_bgs =
false,
1740 .name =
"SpiralStairsGoingUpUpper",
1743 .draws_to_both_bgs =
false,
1752 .name =
"SpiralStairsGoingDownUpper",
1755 .draws_to_both_bgs =
false,
1764 .name =
"SpiralStairsGoingUpLower",
1767 .draws_to_both_bgs =
false,
1776 .name =
"SpiralStairsGoingDownLower",
1779 .draws_to_both_bgs =
false,
1788 .name =
"WaterHopStairsA",
1789 .function = DrawWaterHopStairsA,
1790 .draws_to_both_bgs =
false,
1799 .name =
"WaterHopStairsB",
1800 .function = DrawWaterHopStairsB,
1801 .draws_to_both_bgs =
true,
1810 .name =
"DamFloodGate",
1811 .function = DrawDamFloodGate,
1812 .draws_to_both_bgs =
false,
1822 .name =
"BigKeyLock",
1824 .draws_to_both_bgs =
false,
1833 .name =
"BombableFloor",
1835 .draws_to_both_bgs =
false,
1845 .name =
"EmptyWaterFace",
1847 .draws_to_both_bgs =
false,
1856 .name =
"SpittingWaterFace",
1858 .draws_to_both_bgs =
false,
1867 .name =
"DrenchingWaterFace",
1869 .draws_to_both_bgs =
false,
1880 .name =
"PrisonCell",
1882 .draws_to_both_bgs =
false,
1893 .draws_to_both_bgs =
false,
1901 .name =
"Rightwards3x6",
1903 .draws_to_both_bgs =
false,
1911 .name =
"Utility6x3",
1913 .draws_to_both_bgs =
false,
1921 .name =
"Utility3x5",
1923 .draws_to_both_bgs =
false,
1931 .name =
"VerticalTurtleRockPipe",
1933 .draws_to_both_bgs =
false,
1941 .name =
"HorizontalTurtleRockPipe",
1943 .draws_to_both_bgs =
false,
1951 .name =
"LightBeam",
1953 .draws_to_both_bgs =
false,
1962 .name =
"BigLightBeam",
1964 .draws_to_both_bgs =
false,
1973 .name =
"FloorLight",
1975 .draws_to_both_bgs =
false,
1984 .name =
"BossShell4x4",
1986 .draws_to_both_bgs =
false,
1994 .name =
"VitreousGooDamage",
1996 .draws_to_both_bgs =
false,
2005 .name =
"SolidWallDecor3x4",
2007 .draws_to_both_bgs =
false,
2015 .name =
"ArcheryGameTargetDoor",
2017 .draws_to_both_bgs =
false,
2025 .name =
"GanonTriforceFloorDecor",
2027 .draws_to_both_bgs =
false,
2035 .name =
"Single2x2",
2037 .draws_to_both_bgs =
false,
2046 .name =
"Single4x4",
2048 .draws_to_both_bgs =
false,
2057 .name =
"Single4x3",
2059 .draws_to_both_bgs =
false,
2068 .name =
"RupeeFloor",
2070 .draws_to_both_bgs =
false,
2079 .name =
"Actual4x4",
2081 .draws_to_both_bgs =
false,
2090 .name =
"BigWallDecor",
2092 .draws_to_both_bgs =
false,
2101 .name =
"TableBowl",
2103 .draws_to_both_bgs =
false,
2112 .name =
"SmithyFurnace",
2114 .draws_to_both_bgs =
false,
2123 .name =
"BigGrayRock",
2125 .draws_to_both_bgs =
false,
2134 .name =
"AgahnimsAltar",
2136 .draws_to_both_bgs =
false,
2145 .name =
"FortuneTellerRoom",
2147 .draws_to_both_bgs =
false,
2156 .name =
"MagicBatAltar",
2158 .draws_to_both_bgs =
false,
2167 .name =
"Waterfall47",
2169 .draws_to_both_bgs =
false,
2177 .name =
"Waterfall48",
2179 .draws_to_both_bgs =
false,
2188 .name =
"ClosedChestPlatform",
2190 .draws_to_both_bgs =
false,
2199 .name =
"MovingWallWest",
2201 .draws_to_both_bgs =
false,
2210 .name =
"MovingWallEast",
2212 .draws_to_both_bgs =
false,
2221 .name =
"OpenChestPlatform",
2223 .draws_to_both_bgs =
false,
2233 .name =
"DownwardsHasEdge1x1_1to16_plus23",
2237 int size = ctx.object.size_ & 0x0F;
2238 int count = size + 21;
2239 if (ctx.tiles.size() < 3)
2242 int tile_y = ctx.object.y_;
2246 ctx.target_bg, ctx.object.x_, tile_y, {0x00E3})) {
2252 for (
int s = 0; s < count; s++) {
2261 .draws_to_both_bgs =
false,
2273 .name =
"CustomObject",
2275 .draws_to_both_bgs =
false,
absl::StatusOr< uint16_t > ReadWord(int offset) const
SNES 16-bit tile metadata container.
static CustomObjectManager & Get()
absl::StatusOr< std::shared_ptr< CustomObject > > GetObjectInternal(int object_id, int subtype)
virtual bool IsWaterFaceActive(int room_id) const
virtual bool IsFloorBombable(int room_id) const =0
virtual bool IsWallMoved(int room_id) const =0
virtual bool IsChestOpen(int room_id, int chest_index) const =0
virtual bool IsDoorSwitchActive(int room_id) const =0
virtual bool IsDamFloodgateOpen(int room_id) const
virtual bool IsRupeeFloorCleared(int room_id) const =0
#define LOG_DEBUG(category, format,...)
TileInfo WordToTileInfo(uint16_t word)
constexpr int kGanonTriforceFloorDecor
constexpr int kWaterHopStairsA
constexpr int kArcheryGameTargetDoor
constexpr int kAgahnimsAltar
constexpr int kDamFloodGate
constexpr int kRupeeFloor
constexpr int kWaterfall47
constexpr int kClosedChestPlatform
constexpr int kHorizontalTurtleRockPipe
constexpr int kVitreousGooDamage
constexpr int kBigLightBeam
constexpr int kSolidWallDecor3x4
constexpr int kVerticalTurtleRockPipe
constexpr int kMagicBatAltar
constexpr int kWaterHopStairsB
constexpr int kMovingWallWest
constexpr int kMovingWallEast
constexpr int kBigGrayRock
constexpr int kSmithyFurnace
constexpr int kFloorLight
constexpr int kUtility6x3
constexpr int kCustomObject
constexpr int kOpenChestPlatform
constexpr int kUtility3x5
constexpr int kFortuneTellerRoom
constexpr int kBigWallDecor
constexpr int kRightwards3x6
constexpr int kDownwardsHasEdge1x1_1to16_plus23
constexpr int kBossShell4x4
constexpr int kWaterfall48
bool ExistingTileMatchesAny(const gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::initializer_list< uint16_t > tile_ids)
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
Write an 8x8 tile to the background buffer.
void DrawNx4(const DrawContext &ctx, int columns, size_t start_index)
std::array< gfx::TileInfo, 3 > LoadMovingWallFillTiles(const DrawContext &ctx)
void DrawMovingWallFill(const DrawContext &ctx, int start_x, int column_count, int height)
void DrawRowMajor(gfx::BackgroundBuffer &bg, int base_x, int base_y, int w, int h, std::span< const gfx::TileInfo > tiles, size_t start_index=0)
void DrawOpenChestPlatformSegment(const DrawContext &ctx, int dy, size_t start_index, int fill_width)
void Draw4x4ColumnMajor(const DrawContext &ctx, int x_offset, int y_offset, size_t start_index)
constexpr int kWaterFaceWidthTiles
void DrawWaterHopStairsA(const DrawContext &ctx)
void DrawWaterFaceRows(const DrawContext &ctx, int row_count, int tile_offset)
void Draw1x3NRightwards(const DrawContext &ctx, int columns, size_t start_index, int y_offset=0)
void DrawPlatform3x2(const DrawContext &ctx, int dx, int dy, size_t start_index)
const gfx::TileInfo & TileAtWrapped(std::span< const gfx::TileInfo > tiles, size_t index)
void Draw4x4ColumnMajorTo(gfx::BackgroundBuffer &bg, const RoomObject &object, std::span< const gfx::TileInfo > tiles)
void Draw1x5Column(const DrawContext &ctx, int x_offset, size_t start_index)
void DrawMany32x32Block(gfx::BackgroundBuffer &bg, int base_x, int base_y, std::span< const gfx::TileInfo > tiles)
void DrawFloorLightGrid(const DrawContext &ctx)
void DrawPlatform2x2(const DrawContext &ctx, int dx, int dy, size_t start_index)
constexpr int kMovingWallFillDataOffset
void DrawMovingWallPlatform(const DrawContext &ctx, int direction)
void WritePlatformTile(const DrawContext &ctx, int dx, int dy, size_t index)
void DrawDamFloodGate(const DrawContext &ctx)
void DrawColumnMajor(gfx::BackgroundBuffer &bg, int base_x, int base_y, int w, int h, std::span< const gfx::TileInfo > tiles, size_t start_index=0)
void DrawPlatform1x3Rightwards(const DrawContext &ctx, int dx, int dy, size_t start_index, int columns)
void DrawWaterHopStairsB(const DrawContext &ctx)
constexpr std::array< uint16_t, 3 > kMovingWallFallbackFillWords
void DrawTableRock4x4_1to16(const DrawContext &ctx)
Draw 4x4 table rock pattern.
void DrawInterRoomFatStairsDownA(const DrawContext &ctx)
Draw inter-room fat stairs going down A (Type 2 object 0x12E)
void DrawSingle2x2(const DrawContext &ctx)
Draw a single 2x2 block (column-major order)
void DrawWaterfall47(const DrawContext &ctx)
Draw waterfall object 0x47 pattern.
void DrawHorizontalTurtleRockPipe(const DrawContext &ctx)
Draw horizontal Turtle Rock pipe (6x4)
void DrawAutoStairs(const DrawContext &ctx)
Draw auto stairs (Type 2/3 objects 0x130-0x133, 0x21B-0x21D, 0x233)
void DrawSpittingWaterFace(const DrawContext &ctx)
Draw spitting water face (Type 3 object 0x201)
void DrawAgahnimsAltar(const DrawContext &ctx)
Draw the fixed 14x14 Agahnim altar with mirrored right half.
void DrawLargeCanvasObject(const DrawContext &ctx, int width, int height)
Draw large canvas object with arbitrary dimensions.
void DrawMovingWallEast(const DrawContext &ctx)
Draw the east-moving wall (Type 1 object 0xCE)
void DrawBigGrayRock(const DrawContext &ctx)
Draw the fixed 4x4 big gray rock as two column-major 4x2 bands.
void DrawChest(const DrawContext &ctx, int chest_index)
Draw a small chest with open/closed state support.
void DrawMovingWallWest(const DrawContext &ctx)
Draw the west-moving wall (Type 1 object 0xCD)
void DrawBed4x5(const DrawContext &ctx)
Draw a 4x5 bed pattern (row-major)
void DrawSingle4x4(const DrawContext &ctx)
Draw a single 4x4 block (column-major order)
void DrawUtility3x5(const DrawContext &ctx)
Draw utility 3x5 pattern (special row pattern)
void DrawDoorSwitcherer(const DrawContext &ctx)
Draw door switcher object with state-based graphics.
void Draw4x4BlocksIn4x4SuperSquare(const DrawContext &ctx)
Draw 4x4 solid blocks in a super square grid.
void DrawBigHole4x4_1to16(const DrawContext &ctx)
Draw 4x4 big hole pattern.
void DrawFloorLight(const DrawContext &ctx)
Draw unconditional floor light (8x8 footprint)
void Draw4x4FloorTwoIn4x4SuperSquare(const DrawContext &ctx)
Draw two 4x4 floor pattern variant.
void DrawSolidWallDecor3x4(const DrawContext &ctx)
Draw solid wall decor 3x4.
void DrawLightBeamOnFloor(const DrawContext &ctx)
Draw floor light beam composed of three 4x4 blocks.
void DrawWaterFace(const DrawContext &ctx)
Draw a generic 2x2 water-face helper pattern.
void DrawTableBowl(const DrawContext &ctx)
Draw a fixed 4x2 table bowl in row-major order.
void DrawChestPlatformVerticalWall(const DrawContext &ctx)
Draw chest platform vertical wall section.
void DrawClosedChestPlatform(const DrawContext &ctx)
Draw closed chest platform (Type 1 object 0xC1)
void DrawSmithyFurnace(const DrawContext &ctx)
Draw the fixed 6x8 smithy furnace in row-major order.
void DrawVitreousGooDamage(const DrawContext &ctx)
Draw the fixed 5x2 grid of repeated 4x4 Vitreous goo stamps.
void DrawSpike2x2In4x4SuperSquare(const DrawContext &ctx)
Draw 2x2 spike pattern in super square units.
void DrawSingle4x3(const DrawContext &ctx)
Draw a single 4x3 block (column-major order)
void DrawBigLightBeamOnFloor(const DrawContext &ctx)
Draw state-gated big floor light beam active variant (8x8 footprint)
void DrawOpenChestPlatform(const DrawContext &ctx)
Draw open chest platform (Type 1 object 0xDC)
void DrawSpiralStairs(const DrawContext &ctx, bool going_up, bool is_upper)
Draw spiral stairs (Type 2 objects 0x138-0x13B)
void DrawFortuneTellerRoom(const DrawContext &ctx)
Draw the fixed 14x14 fortune teller room on BG1.
void DrawSomariaLine(const DrawContext &ctx)
Draw one Somaria path tile at the object anchor.
void DrawWaterfall48(const DrawContext &ctx)
Draw waterfall object 0x48 pattern.
void DrawVerticalTurtleRockPipe(const DrawContext &ctx)
Draw vertical Turtle Rock pipe (two stacked 4x3 sections)
void DrawBombableFloor(const DrawContext &ctx)
Draw bombable floor (Type 3 object 0xFC7 / ASM object 0x247)
void DrawDrenchingWaterFace(const DrawContext &ctx)
Draw drenching water face (Type 3 object 0x202)
void DrawEmptyWaterFace(const DrawContext &ctx)
Draw empty water face (Type 3 object 0x200)
void DrawBossShell4x4(const DrawContext &ctx)
Draw boss shell 4x4.
void CustomDraw(const DrawContext &ctx)
Custom draw routine for special objects.
void DrawBigWallDecor(const DrawContext &ctx)
Draw fixed 8x3 big wall decor in column-major order.
void Draw4x4FloorIn4x4SuperSquare(const DrawContext &ctx)
Draw 4x4 floor pattern in super square units.
void DrawInterRoomFatStairsUp(const DrawContext &ctx)
Draw inter-room fat stairs going up (Type 2 object 0x12D)
void Draw3x3FloorIn4x4SuperSquare(const DrawContext &ctx)
Draw 3x3 floor pattern in super square units.
void DrawArcheryGameTargetDoor(const DrawContext &ctx)
Draw archery game target door (two 3x3 sections)
void DrawStraightInterRoomStairs(const DrawContext &ctx)
Draw straight inter-room stairs (Type 3 objects 0x21E-0x229)
void DrawGanonTriforceFloorDecor(const DrawContext &ctx)
Draw Ganon triforce floor decor (three 4x4 sections)
void RegisterSpecialRoutines(std::vector< DrawRoutineInfo > ®istry)
Register all special/miscellaneous draw routines to the registry.
void DrawInterRoomFatStairsDownB(const DrawContext &ctx)
Draw inter-room fat stairs going down B (Type 2 object 0x12F)
void DrawUtility6x3(const DrawContext &ctx)
Draw utility 6x3 pattern via RoomDraw_1x3N_rightwards.
void DrawRightwards3x6(const DrawContext &ctx)
Draw a 6x3 pattern via RoomDraw_1x3N_rightwards semantics.
void DrawMagicBatAltar(const DrawContext &ctx)
Draw the fixed 8x7 Magic Bat altar in column-major order.
void DrawChestPlatformHorizontalWall(const DrawContext &ctx)
Draw chest platform horizontal wall section.
void DrawWaterOverlay8x8_1to16(const DrawContext &ctx)
Draw water overlay 8x8 pattern.
void DrawRupeeFloor(const DrawContext &ctx)
Draw the blue rupee floor pattern (5x8 bounds with gaps)
void Draw4x4FloorOneIn4x4SuperSquare(const DrawContext &ctx)
Draw single 4x4 floor pattern variant.
void DrawNothing(const DrawContext &ctx)
Draw nothing - represents invisible logic objects or placeholders.
void DrawActual4x4(const DrawContext &ctx)
Draw an actual 4x4 tile8 pattern (column-major order)
void DrawBigKeyLock(const DrawContext &ctx)
Draw a closed big key lock (Yaze 0xF98 / ASM object 0x218)
void DrawPrisonCell(const DrawContext &ctx)
Draw prison cell with bars (Type 3 objects 0x20D, 0x217)
constexpr int DirectionForSize(int size)
constexpr int ObjectCountForSize(int size)
constexpr bool IsFullBothAutoStairsObject(int object_id)
constexpr bool IsSouthMixedStraightInterroomObject(int object_id)
constexpr bool IsMixedStraightInterroomObject(int object_id)
constexpr bool IsFixedBg1StraightInterroomObject(int object_id)
constexpr int kRoomObjectTileAddress
Context passed to draw routines containing all necessary state.
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
const RoomObject & object
gfx::BackgroundBuffer * secondary_bg
const DungeonState * state
Metadata about a draw routine.