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) {
314 if (!result.ok() || !result.value()) {
316 if (ctx.
tiles.size() >= 1) {
323 const auto& custom_obj = *result.value();
324 if (custom_obj.IsEmpty()) {
329 for (
const auto& entry : custom_obj.tiles) {
332 if (entry.tile_data == 0) {
336 const uint16_t runtime_word =
342 int draw_x = ctx.
object.
x_ + entry.rel_x;
343 int draw_y = ctx.
object.
y_ + entry.rel_y;
356 if (ctx.
tiles.size() >= 2) {
361 if (ctx.
tiles.size() >
static_cast<size_t>(tile_index)) {
363 ctx.
tiles[tile_index]);
371 if (ctx.
tiles.empty()) {
383 if (ctx.
tiles.size() >= 4) {
400 if (ctx.
tiles.size() >=
static_cast<size_t>(width * height)) {
401 for (
int y = 0; y < height; ++y) {
402 for (
int x = 0; x < width; ++x) {
405 ctx.
tiles[y * width + x]);
419 Draw1x3NRightwards(ctx, 6, 0);
424 Draw1x3NRightwards(ctx, 6, 0);
430 Draw1x3NRightwards(ctx, 8, 0);
436 if (ctx.
tiles.size() < 8)
445 if (ctx.
tiles.size() < 48)
460 if (ctx.
tiles.size() < 16)
474 if (ctx.
tiles.size() < 84)
477 constexpr std::array<int, 14> kSourceColumns = {
478 0, 1, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1, 0,
480 for (
int y = 0; y < 14; ++y) {
481 for (
int x = 0; x < 14; ++x) {
483 if (x >= 7 && x <= 12) {
485 }
else if (x == 13) {
497 if (ctx.
tiles.size() < 26)
500 auto write = [&](
int dx,
int dy,
size_t tile_index,
501 bool force_horizontal_mirror =
false,
502 bool toggle_horizontal_mirror =
false) {
504 if (force_horizontal_mirror) {
506 }
else if (toggle_horizontal_mirror) {
514 for (
int section = 0; section < 6; ++section) {
515 const int x = section * 2;
521 write(x + 2, 2, 1,
true);
526 for (
int row = 0; row < 3; ++row) {
527 const size_t wall_tile =
static_cast<size_t>(2 + row);
528 const size_t center_tile =
static_cast<size_t>(5 + row);
529 const int y = 3 + row;
531 for (
int x : {0, 2, 10, 12}) {
532 write(x, y, wall_tile);
534 for (
int x : {1, 3, 11, 13}) {
535 write(x, y, wall_tile,
true);
537 for (
int x : {4, 6, 8}) {
538 write(x, y, center_tile);
540 for (
int x : {5, 7, 9}) {
541 write(x, y, center_tile,
true);
548 write(13, 0, 8,
true);
549 write(13, 1, 8,
true);
551 write(13, 2, 9,
true);
555 for (
int row = 0; row < 4; ++row) {
556 const int y = 10 + row;
557 write(3, y,
static_cast<size_t>(10 + row));
558 write(10, y,
static_cast<size_t>(10 + row),
561 write(4, y,
static_cast<size_t>(14 + row));
562 write(9, y,
static_cast<size_t>(14 + row),
565 write(5, y,
static_cast<size_t>(18 + row));
566 write(8, y,
static_cast<size_t>(18 + row),
569 write(6, y,
static_cast<size_t>(22 + row));
570 write(7, y,
static_cast<size_t>(22 + row),
580 if (ctx.
tiles.size() < 56)
591 if (ctx.
tiles.empty())
595 for (
int x = 0; x < 3; ++x) {
598 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(x)));
602 for (
int y = 1; y <= 3; ++y) {
603 for (
int x = 0; x < 3; ++x) {
606 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(3 + x)));
611 for (
int x = 0; x < 3; ++x) {
614 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(6 + x)));
621 if (ctx.
tiles.empty())
623 Draw1x3NRightwards(ctx, 4, 0, 0);
624 Draw1x3NRightwards(ctx, 4, 12, 3);
637 if (ctx.
tiles.size() < 32)
639 Draw4x4ColumnMajor(ctx, 0, 0, 0);
640 Draw4x4ColumnMajor(ctx, 0, 2, 0);
641 Draw4x4ColumnMajor(ctx, 0, 6, 16);
650 if (ctx.
state !=
nullptr &&
654 DrawFloorLightGrid(ctx);
659 DrawFloorLightGrid(ctx);
664 Draw4x4ColumnMajor(ctx, 0, 0, 0);
672 if (ctx.
tiles.size() < 8)
675 for (
int block_y = 0; block_y < 2; ++block_y) {
676 for (
int block_x = 0; block_x < 5; ++block_x) {
691 if (ctx.
tiles.empty())
693 Draw1x3NRightwards(ctx, 3, 0, 0);
694 Draw1x3NRightwards(ctx, 3, 9, 3);
700 if (ctx.
tiles.empty())
703 Draw4x4ColumnMajor(ctx, 2, 0, 0);
704 Draw4x4ColumnMajor(ctx, 0, 4, 16);
705 Draw4x4ColumnMajor(ctx, 4, 4, 16);
711 if (ctx.
tiles.size() < 4)
726 if (ctx.
tiles.size() < 16)
730 for (
int x = 0; x < 4; ++x) {
731 for (
int y = 0; y < 4; ++y) {
740 if (ctx.
tiles.size() < 12)
744 for (
int x = 0; x < 4; ++x) {
745 for (
int y = 0; y < 3; ++y) {
757 ctx.
tiles.size() < 2) {
761 constexpr std::array<int, 3> kTopRows = {0, 3, 6};
762 constexpr std::array<int, 3> kBottomRows = {1, 4, 7};
763 for (
int col = 0; col < 3; ++col) {
764 const int x = ctx.
object.
x_ + col * 2;
765 for (
int row : kTopRows) {
769 for (
int row : kBottomRows) {
784 if (ctx.
tiles.empty())
788 const int middle_columns = (size + 1) * 2;
790 Draw1x5Column(ctx, 0, 0);
791 for (
int i = 0; i < middle_columns; ++i) {
792 Draw1x5Column(ctx, 1 + i, 5);
794 Draw1x5Column(ctx, 1 + middle_columns, 10);
800 if (ctx.
tiles.empty())
804 const int middle_columns = (size + 1) * 2;
808 for (
int i = 0; i < middle_columns; ++i) {
831 "Draw4x4BlocksIn4x4SuperSquare: obj=0x%03X pos=(%d,%d) size=0x%02X "
832 "tiles=%zu size_x=%d size_y=%d",
834 ctx.
tiles.size(), size_x, size_y);
836 if (ctx.
tiles.empty()) {
838 "Draw4x4BlocksIn4x4SuperSquare: SKIPPING - no tiles loaded!");
843 const auto& tile = ctx.
tiles[0];
845 "Draw4x4BlocksIn4x4SuperSquare: tile[0] id=%d palette=%d", tile.id_,
848 for (
int sy = 0; sy < size_y; ++sy) {
849 for (
int sx = 0; sx < size_x; ++sx) {
851 int base_x = ctx.
object.
x_ + (sx * 4);
852 int base_y = ctx.
object.
y_ + (sy * 4);
855 for (
int y = 0; y < 4; ++y) {
856 for (
int x = 0; x < 4; ++x) {
871 if (ctx.
tiles.empty())
874 const auto& tile = ctx.
tiles[0];
875 for (
int sy = 0; sy < size_y; ++sy) {
876 for (
int sx = 0; sx < size_x; ++sx) {
877 int base_x = ctx.
object.
x_ + (sx * 3);
878 int base_y = ctx.
object.
y_ + (sy * 3);
880 for (
int y = 0; y < 3; ++y) {
881 for (
int x = 0; x < 3; ++x) {
897 if (ctx.
tiles.empty())
899 if (ctx.
tiles.size() < 8) {
906 for (
int sy = 0; sy < size_y; ++sy) {
907 for (
int sx = 0; sx < size_x; ++sx) {
908 int base_x = ctx.
object.
x_ + (sx * 4);
909 int base_y = ctx.
object.
y_ + (sy * 4);
933 if (ctx.
tiles.size() < 24)
950 for (
int xx = 1; xx < max; ++xx) {
951 for (
int yy = 1; yy < max; ++yy) {
961 for (
int yy = 1; yy < max; ++yy) {
975 if (ctx.
tiles.size() < 4)
978 for (
int sy = 0; sy < size_y; ++sy) {
979 for (
int sx = 0; sx < size_x; ++sx) {
980 int base_x = ctx.
object.
x_ + (sx * 2);
981 int base_y = ctx.
object.
y_ + (sy * 2);
999 if (ctx.
tiles.size() < 16)
1002 int right_x = ctx.
object.
x_ + (3 + (size_x * 2));
1003 int bottom_y = ctx.
object.
y_ + (3 + (size_y * 2));
1006 for (
int xx = 0; xx < size_x + 1; ++xx) {
1007 for (
int yy = 0; yy < size_y + 1; ++yy) {
1008 int base_x = ctx.
object.
x_ + (xx * 2);
1009 int base_y = ctx.
object.
y_ + (yy * 2);
1022 for (
int yy = 0; yy < size_y + 1; ++yy) {
1023 int base_y = ctx.
object.
y_ + (yy * 2);
1036 for (
int xx = 0; xx < size_x + 1; ++xx) {
1037 int base_x = ctx.
object.
x_ + (xx * 2);
1069 int count_x = size_x + 2;
1070 int count_y = size_y + 2;
1072 if (ctx.
tiles.empty())
1074 if (ctx.
tiles.size() < 8) {
1076 for (
int yy = 0; yy < count_y; ++yy) {
1077 for (
int xx = 0; xx < count_x; ++xx) {
1078 int base_x = ctx.
object.
x_ + (xx * 4);
1079 int base_y = ctx.
object.
y_ + (yy * 4);
1081 ctx.
tiles[
static_cast<size_t>((xx + yy) % ctx.
tiles.size())];
1082 for (
int y = 0; y < 4; ++y) {
1083 for (
int x = 0; x < 4; ++x) {
1093 for (
int yy = 0; yy < count_y; ++yy) {
1094 for (
int xx = 0; xx < count_x; ++xx) {
1095 int base_x = ctx.
object.
x_ + (xx * 4);
1096 int base_y = ctx.
object.
y_ + (yy * 4);
1098 for (
int x = 0; x < 4; ++x) {
1122 if (ctx.
tiles.size() < 16)
1150 if (ctx.
tiles.size() < 12)
1160 if (ctx.
tiles.size() < 16)
1175 if (ctx.
tiles.size() < 16)
1186 const bool south_lower =
1189 size_t tile_index = 0;
1190 for (
int col = 0; col < 4; ++col) {
1191 for (
int row = 0; row < 4; ++row) {
1192 const auto& tile = TileAtWrapped(ctx.
tiles, tile_index++);
1195 if ((!south_lower && row == 0) || (south_lower && row == 3)) {
1214 if (ctx.
tiles.size() < 6) {
1224 tile.horizontal_mirror_ =
true;
1228 for (
int col = 0; col < 5; ++col) {
1229 const int left_x = base_x + 2 + col;
1230 const int right_x = base_x + 9 + col;
1236 with_horizontal_mirror(ctx.
tiles[2]));
1240 with_horizontal_mirror(ctx.
tiles[4]));
1244 with_horizontal_mirror(ctx.
tiles[5]));
1249 with_horizontal_mirror(ctx.
tiles[0]));
1250 for (
int x_offset : {1, 7, 8, 14}) {
1257 with_horizontal_mirror(ctx.
tiles[3]));
1274 if (ctx.
tiles.size() < 16) {
1281 const bool is_open = ctx.
state !=
nullptr &&
1283 ctx.
tiles.size() >= 32;
1284 const size_t state_offset = is_open ? 16 : 0;
1286 for (
int block_y = 0; block_y < 2; ++block_y) {
1287 for (
int block_x = 0; block_x < 2; ++block_x) {
1288 const size_t block_offset =
1289 state_offset +
static_cast<size_t>((block_y * 2 + block_x) * 4);
1290 for (
int x = 0; x < 2; ++x) {
1291 for (
int y = 0; y < 2; ++y) {
1295 ctx.
tiles[block_offset +
static_cast<size_t>(x * 2 + y)]);
1305 ctx.
tiles.size() < 24) {
1311 const int height = direction * 2 + 6;
1315 DrawMovingWallFill(ctx, ctx.
object.
x_ - column_count, column_count, height);
1316 DrawMovingWallPlatform(ctx, direction);
1322 ctx.
tiles.size() < 24) {
1328 const int height = direction * 2 + 6;
1332 DrawMovingWallPlatform(ctx, direction);
1333 DrawMovingWallFill(ctx, ctx.
object.
x_ + 3, column_count, height);
1344 if (row_count <= 0 || tile_offset < 0 || ctx.
tiles.empty()) {
1348 if (tile_offset >=
static_cast<int>(ctx.
tiles.size())) {
1352 const int available_tiles =
static_cast<int>(ctx.
tiles.size()) - tile_offset;
1354 const int rows_to_draw = std::min(row_count, available_rows);
1356 for (
int row = 0; row < rows_to_draw; ++row) {
1361 ctx.
tiles[row_base + col]);
1376 const bool water_active =
1379 const int row_count = water_active ? 5 : 3;
1380 const int tile_offset = water_active ? 12 : 0;
1381 DrawWaterFaceRows(ctx, row_count, tile_offset);
1387 DrawWaterFaceRows(ctx, 5, 0);
1393 DrawWaterFaceRows(ctx, 7, 0);
1407 if (ctx.
tiles.size() < 68)
1410 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1412 const int width_blocks = size_x + 4;
1413 const int height_blocks = size_y + 1;
1416 DrawPlatform1x3Rightwards(ctx, 0, 0, 0,
1418 for (
int x = 0; x < width_blocks; ++x) {
1419 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, 0,
1422 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, 0,
1426 for (
int y = 0; y < height_blocks; ++y) {
1427 const int dy = 3 + y * 2;
1428 DrawPlatform3x2(ctx, 0, dy, 24);
1429 for (
int x = 0; x < width_blocks; ++x) {
1430 DrawPlatform2x2(ctx, 3 + x * 2, dy, 30);
1432 DrawPlatform3x2(ctx, 3 + width_blocks * 2, dy,
1437 const int bottom_y = 3 + height_blocks * 2;
1438 DrawPlatform1x3Rightwards(ctx, 0, bottom_y, 40,
1440 for (
int x = 0; x < width_blocks; ++x) {
1441 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, bottom_y,
1444 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, bottom_y,
1449 DrawPlatform2x2(ctx, width_blocks + 2,
1450 bottom_y - (height_blocks + 1),
1458 if (ctx.
tiles.size() < 21)
1461 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1463 const int fill_width = size_x + 1;
1464 const int body_rows = size_y * 2 + 5;
1466 for (
int row = 0; row < body_rows; ++row) {
1467 DrawOpenChestPlatformSegment(ctx, row, 0, fill_width);
1469 DrawOpenChestPlatformSegment(ctx, body_rows, 1, fill_width);
1470 DrawOpenChestPlatformSegment(ctx, body_rows + 1, 2,
1478 if (ctx.
tiles.size() < 3)
1481 for (
int x = 0; x < width; ++x) {
1482 size_t tile_idx = (x == 0) ? 0 : ((x == width - 1) ? 2 : 1);
1492 if (ctx.
tiles.empty())
1495 for (
int y = 0; y < height; ++y) {
1514 .draws_to_both_bgs =
false,
1525 .draws_to_both_bgs =
false,
1533 .name =
"DoorSwitcherer",
1535 .draws_to_both_bgs =
false,
1544 .name =
"SomariaLine",
1546 .draws_to_both_bgs =
false,
1555 .name =
"WaterFace",
1557 .draws_to_both_bgs =
false,
1570 .name =
"4x4BlocksIn4x4SuperSquare",
1572 .draws_to_both_bgs =
false,
1580 .name =
"3x3FloorIn4x4SuperSquare",
1582 .draws_to_both_bgs =
false,
1590 .name =
"4x4FloorIn4x4SuperSquare",
1592 .draws_to_both_bgs =
false,
1600 .name =
"4x4FloorOneIn4x4SuperSquare",
1602 .draws_to_both_bgs =
false,
1610 .name =
"4x4FloorTwoIn4x4SuperSquare",
1612 .draws_to_both_bgs =
false,
1620 .name =
"BigHole4x4_1to16",
1622 .draws_to_both_bgs =
false,
1630 .name =
"Spike2x2In4x4SuperSquare",
1632 .draws_to_both_bgs =
false,
1640 .name =
"TableRock4x4_1to16",
1642 .draws_to_both_bgs =
false,
1650 .name =
"WaterOverlay8x8_1to16",
1652 .draws_to_both_bgs =
false,
1661 .name =
"InterRoomFatStairsUp",
1663 .draws_to_both_bgs =
false,
1672 .name =
"InterRoomFatStairsDownA",
1674 .draws_to_both_bgs =
false,
1683 .name =
"InterRoomFatStairsDownB",
1685 .draws_to_both_bgs =
false,
1694 .name =
"AutoStairs",
1696 .draws_to_both_bgs =
false,
1705 .name =
"StraightInterRoomStairs",
1707 .draws_to_both_bgs =
false,
1717 .name =
"SpiralStairsGoingUpUpper",
1720 .draws_to_both_bgs =
false,
1729 .name =
"SpiralStairsGoingDownUpper",
1732 .draws_to_both_bgs =
false,
1741 .name =
"SpiralStairsGoingUpLower",
1744 .draws_to_both_bgs =
false,
1753 .name =
"SpiralStairsGoingDownLower",
1756 .draws_to_both_bgs =
false,
1765 .name =
"WaterHopStairsA",
1766 .function = DrawWaterHopStairsA,
1767 .draws_to_both_bgs =
false,
1776 .name =
"WaterHopStairsB",
1777 .function = DrawWaterHopStairsB,
1778 .draws_to_both_bgs =
true,
1787 .name =
"DamFloodGate",
1788 .function = DrawDamFloodGate,
1789 .draws_to_both_bgs =
false,
1799 .name =
"BigKeyLock",
1801 .draws_to_both_bgs =
false,
1810 .name =
"BombableFloor",
1812 .draws_to_both_bgs =
false,
1822 .name =
"EmptyWaterFace",
1824 .draws_to_both_bgs =
false,
1833 .name =
"SpittingWaterFace",
1835 .draws_to_both_bgs =
false,
1844 .name =
"DrenchingWaterFace",
1846 .draws_to_both_bgs =
false,
1857 .name =
"PrisonCell",
1859 .draws_to_both_bgs =
false,
1870 .draws_to_both_bgs =
false,
1878 .name =
"Rightwards3x6",
1880 .draws_to_both_bgs =
false,
1888 .name =
"Utility6x3",
1890 .draws_to_both_bgs =
false,
1898 .name =
"Utility3x5",
1900 .draws_to_both_bgs =
false,
1908 .name =
"VerticalTurtleRockPipe",
1910 .draws_to_both_bgs =
false,
1918 .name =
"HorizontalTurtleRockPipe",
1920 .draws_to_both_bgs =
false,
1928 .name =
"LightBeam",
1930 .draws_to_both_bgs =
false,
1939 .name =
"BigLightBeam",
1941 .draws_to_both_bgs =
false,
1950 .name =
"FloorLight",
1952 .draws_to_both_bgs =
false,
1961 .name =
"BossShell4x4",
1963 .draws_to_both_bgs =
false,
1971 .name =
"VitreousGooDamage",
1973 .draws_to_both_bgs =
false,
1982 .name =
"SolidWallDecor3x4",
1984 .draws_to_both_bgs =
false,
1992 .name =
"ArcheryGameTargetDoor",
1994 .draws_to_both_bgs =
false,
2002 .name =
"GanonTriforceFloorDecor",
2004 .draws_to_both_bgs =
false,
2012 .name =
"Single2x2",
2014 .draws_to_both_bgs =
false,
2023 .name =
"Single4x4",
2025 .draws_to_both_bgs =
false,
2034 .name =
"Single4x3",
2036 .draws_to_both_bgs =
false,
2045 .name =
"RupeeFloor",
2047 .draws_to_both_bgs =
false,
2056 .name =
"Actual4x4",
2058 .draws_to_both_bgs =
false,
2067 .name =
"BigWallDecor",
2069 .draws_to_both_bgs =
false,
2078 .name =
"TableBowl",
2080 .draws_to_both_bgs =
false,
2089 .name =
"SmithyFurnace",
2091 .draws_to_both_bgs =
false,
2100 .name =
"BigGrayRock",
2102 .draws_to_both_bgs =
false,
2111 .name =
"AgahnimsAltar",
2113 .draws_to_both_bgs =
false,
2122 .name =
"FortuneTellerRoom",
2124 .draws_to_both_bgs =
false,
2133 .name =
"MagicBatAltar",
2135 .draws_to_both_bgs =
false,
2144 .name =
"Waterfall47",
2146 .draws_to_both_bgs =
false,
2154 .name =
"Waterfall48",
2156 .draws_to_both_bgs =
false,
2165 .name =
"ClosedChestPlatform",
2167 .draws_to_both_bgs =
false,
2176 .name =
"MovingWallWest",
2178 .draws_to_both_bgs =
false,
2187 .name =
"MovingWallEast",
2189 .draws_to_both_bgs =
false,
2198 .name =
"OpenChestPlatform",
2200 .draws_to_both_bgs =
false,
2210 .name =
"DownwardsHasEdge1x1_1to16_plus23",
2214 int size = ctx.object.size_ & 0x0F;
2215 int count = size + 21;
2216 if (ctx.tiles.size() < 3)
2219 int tile_y = ctx.object.y_;
2223 tile_y, {0x00E3})) {
2229 for (
int s = 0; s < count; s++) {
2238 .draws_to_both_bgs =
false,
2250 .name =
"CustomObject",
2252 .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)
uint16_t CustomObjectRuntimeTileWord(int object_id, uint16_t source_word)
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.